www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - va_start/va_end

reply J Anderson <REMOVEanderson badmama.com.au> writes:
What are the equivalent of:
va_start
and
va_end

in D?

Thanks.

PS - This is not meant to be an argument in anyway.  I just want to use 
the ... for multiple arguments.

-- 
-Anderson: http://badmama.com.au/~anderson/
May 01 2004
parent reply "Andrew Edwards" <edwardsac spamfreeusa.com> writes:
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c716pl$1ljo$1 digitaldaemon.com...
 What are the equivalent of:
 va_start
 and
 va_end

 in D?

 Thanks.

 PS - This is not meant to be an argument in anyway.  I just want to use
 the ... for multiple arguments.

 -- 
 -Anderson: http://badmama.com.au/~anderson/

There is no equivalent...You need to roll your own. I had played with this before, but am not sure if I came up with the correct syntax as I'm still having problems with it. void va_start(inout va_list ap, char[] fmt) { ap = cast(void*)(&args+args.size); } void va_end(inout va_list ap) { ap = null; } if you come up with something that works please I'd like to get a hold of it. Thanks, Andrew
May 01 2004
next sibling parent reply "Andrew Edwards" <edwardsac spamfreeusa.com> writes:
"Andrew Edwards" <edwardsac spamfreeusa.com> wrote in message
news:c71m0d$2ck4$1 digitaldaemon.com...
 "J Anderson" <REMOVEanderson badmama.com.au> wrote in message
 news:c716pl$1ljo$1 digitaldaemon.com...
 What are the equivalent of:
 va_start
 and
 va_end

 in D?

 Thanks.

 PS - This is not meant to be an argument in anyway.  I just want to use
 the ... for multiple arguments.

 -- 
 -Anderson: http://badmama.com.au/~anderson/

There is no equivalent...You need to roll your own. I had played with this before, but am not sure if I came up with the correct syntax as I'm still having problems with it. void va_start(inout va_list ap, char[] fmt) { ap = cast(void*)(&args+args.size); }

sorry , that should read: ap = cast(va_list*)(&ap+ap.size);
 void va_end(inout va_list ap)
 {
   ap = null;
 }

 if you come up with something that works please I'd like to get a hold of
 it.

 Thanks,
 Andrew

May 01 2004
parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Andrew Edwards wrote:

"Andrew Edwards" <edwardsac spamfreeusa.com> wrote in message
news:c71m0d$2ck4$1 digitaldaemon.com...
  

"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c716pl$1ljo$1 digitaldaemon.com...
    

What are the equivalent of:
va_start
and
va_end

in D?

Thanks.

PS - This is not meant to be an argument in anyway.  I just want to use
the ... for multiple arguments.

-- 
-Anderson: http://badmama.com.au/~anderson/
      

before, but am not sure if I came up with the correct syntax as I'm still having problems with it. void va_start(inout va_list ap, char[] fmt) { ap = cast(void*)(&args+args.size); }

sorry , that should read: ap = cast(va_list*)(&ap+ap.size);

I don't get it, where do I get the parameter input from? For example, at the moment I've got something like this: void printp(char *format, ... ) { char [] TempStr; TempStr.length = (strlen((char*)format) * 2) + 50; //Guess va_list varg; //Holds arguments //Open the argument list va_start(varg,format); //Generate the string int x = _vsnprintf(TempStr, TempStr.length - 1, format, varg); //Increase size until it fits (not to efficient, but no overflows) while (x == -1) { //Increase size TempStr.length += 100; x = _vsnprintf(TempStr, TempStr.length - 1, format, varg); } //Close the argument list va_end(varg); } Of course the va_start doesn't work. Thanks. -- -Anderson: http://badmama.com.au/~anderson/
May 01 2004
next sibling parent J Anderson <REMOVEanderson badmama.com.au> writes:
J Anderson wrote:

 Andrew Edwards wrote:

 "Andrew Edwards" <edwardsac spamfreeusa.com> wrote in message
 news:c71m0d$2ck4$1 digitaldaemon.com...
  

 "J Anderson" <REMOVEanderson badmama.com.au> wrote in message
 news:c716pl$1ljo$1 digitaldaemon.com...
   

 What are the equivalent of:
 va_start
 and
 va_end

 in D?

 Thanks.

 PS - This is not meant to be an argument in anyway.  I just want to 
 use
 the ... for multiple arguments.

 -- 
 -Anderson: http://badmama.com.au/~anderson/
     

There is no equivalent...You need to roll your own. I had played with this before, but am not sure if I came up with the correct syntax as I'm still having problems with it. void va_start(inout va_list ap, char[] fmt) { ap = cast(void*)(&args+args.size); }

sorry , that should read: ap = cast(va_list*)(&ap+ap.size);

I don't get it, where do I get the parameter input from? For example, at the moment I've got something like this: void printp(char *format, ... ) { char [] TempStr; TempStr.length = (strlen((char*)format) * 2) + 50; //Guess va_list varg; //Holds arguments //Open the argument list va_start(varg,format); //Generate the string int x = _vsnprintf(TempStr, TempStr.length - 1, format, varg); //Increase size until it fits (not to efficient, but no overflows) while (x == -1) { //Increase size TempStr.length += 100; x = _vsnprintf(TempStr, TempStr.length - 1, format, varg); } //Close the argument list va_end(varg); } Of course the va_start doesn't work. Thanks.

-- -Anderson: http://badmama.com.au/~anderson/
May 02 2004
prev sibling parent "Walter" <newshound digitalmars.com> writes:
Replace the va_start with:

    varg = (void*)&format + (void*).size;

Replace va_end with nothing.

"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c71qcc$2jnr$1 digitaldaemon.com...
 Andrew Edwards wrote:

"Andrew Edwards" <edwardsac spamfreeusa.com> wrote in message
news:c71m0d$2ck4$1 digitaldaemon.com...


"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:c716pl$1ljo$1 digitaldaemon.com...


What are the equivalent of:
va_start
and
va_end

in D?

Thanks.

PS - This is not meant to be an argument in anyway.  I just want to use
the ... for multiple arguments.

-- 
-Anderson: http://badmama.com.au/~anderson/




before, but am not sure if I came up with the correct syntax as I'm



having problems with it.

void va_start(inout va_list ap, char[] fmt)
{
  ap = cast(void*)(&args+args.size);
}

sorry , that should read: ap = cast(va_list*)(&ap+ap.size);

I don't get it, where do I get the parameter input from? For example, at the moment I've got something like this: void printp(char *format, ... ) { char [] TempStr; TempStr.length = (strlen((char*)format) * 2) + 50; //Guess va_list varg; //Holds arguments //Open the argument list va_start(varg,format); //Generate the string int x = _vsnprintf(TempStr, TempStr.length - 1, format, varg); //Increase size until it fits (not to efficient, but no overflows) while (x == -1) { //Increase size TempStr.length += 100; x = _vsnprintf(TempStr, TempStr.length - 1, format, varg); } //Close the argument list va_end(varg); } Of course the va_start doesn't work. Thanks. -- -Anderson: http://badmama.com.au/~anderson/

May 02 2004
prev sibling next sibling parent Ben Hinkle <bhinkle4 juno.com> writes:
 void va_start(inout va_list ap, char[] fmt)
 {
   ap = cast(void*)(&args+args.size);
 }
 
 void va_end(inout va_list ap)
 {
   ap = null;
 }

It's a bummer but I don't think "global" va_start and friends can be written without macros. I'd look at the printf code in std.outbuffer or std.stream for examples of how to use varargs in D. Maybe using nested functions would work but it wouldn't be very practical to have to define va_start inside every function that uses it. -Ben
May 01 2004
prev sibling parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Andrew Edwards wrote:
 "J Anderson" <REMOVEanderson badmama.com.au> wrote in message
 news:c716pl$1ljo$1 digitaldaemon.com...
 
What are the equivalent of:
va_start
and
va_end

in D?

Thanks.

PS - This is not meant to be an argument in anyway.  I just want to use
the ... for multiple arguments.

-- 
-Anderson: http://badmama.com.au/~anderson/

There is no equivalent...You need to roll your own. I had played with this before, but am not sure if I came up with the correct syntax as I'm still having problems with it. void va_start(inout va_list ap, char[] fmt) { ap = cast(void*)(&args+args.size); } void va_end(inout va_list ap) { ap = null; }

This is wrong. ap is allocated on the stack AFTER the variable arguments. I'm not sure about the D calling convention, but when parameters are pushed in-order then it would have to look something like this: void va_start(out va_list ap, inout void* prevArg) { ap = (&prevArg)+prevArg.size; } This will only work if the previous argument is a pointer, though. A template helps: typedef void* va_list; template va_start(T) { void va_start(out va_list ap, inout T prevArg) { ap = (cast(void*)&prevArg)+prevArg.size; } } template va_arg(T) { T va_arg(inout va_list ap) { T arg=*cast(T*)ap; ap+=T.size; return arg; } } Unfortunately, since we have no implicit template instantiation, you then have to use it like this: void printf(char[] fmt,...) { va_list ap; va_start!(char[])(ap,fmt); if(....) int param=va_arg!(int)(ap); }
May 02 2004
next sibling parent Hauke Duden <H.NS.Duden gmx.net> writes:
Hauke Duden wrote:
 This is wrong. ap is allocated on the stack AFTER the variable 
 arguments. I'm not sure about the D calling convention, but when 
 parameters are pushed in-order then it would have to look something like 
 this:

Just realized my error here: if the stack grows downwards (which, if memory serves, it usually does) and the arguments are still pushed in-order then this must look a little different: typedef void* va_list; template va_start(T) { void va_start(out va_list ap, inout T prevArg) { ap = cast(void*)&prevArg; } } template va_arg(T) { T va_arg(inout va_list ap) { ap-=T.size; return *cast(T*)ap; } } Hauke
May 02 2004
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
Your use of templates to do varargs is cool. I made a couple of fixes, and
the result is std.stdarg! It'll go out in the next release.

-------------------------------------------------
/*
 * Placed in public domain.
 * Written by Hauke Duden and Walter Bright
 */

module std.stdarg;

typedef void* va_list;

template va_start(T)
{
    void va_start(out va_list ap, inout T parmn)
    {
 ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) &
~(int.sizeof - 1)));
    }
}

template va_arg(T)
{
    T va_arg(inout va_list ap)
    {
 T arg = *cast(T*)ap;
 ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) &
~(int.sizeof - 1)));
 return arg;
    }
}

void va_end(va_list ap)
{
}
------------------------------------------------------------------
Here's a little test program to show how to use it:

------------------------------------------------------------------
import std.stdarg;

int foo(char *x, ...)
{
    va_list ap;

    va_start!(typeof(x))(ap, x);
    printf("&x = %p, ap = %p\n", &x, ap);

    int i;
    i = va_arg!(typeof(i))(ap);
    printf("i = %d\n", i);

    long l;
    l = va_arg!(typeof(l))(ap);
    printf("l = %lld\n", l);

    uint k;
    k = va_arg!(typeof(k))(ap);
    printf("k = %u\n", k);

    va_end(ap);

    return i + l + k;
}

void main()
{
    int j;

    j = foo("hello", 3, 23L, 4);
    printf("j = %d\n", j);
    assert(j == 30);
}
------------------------------------------------------
May 02 2004
next sibling parent reply J C Calvarese <jcc7 cox.net> writes:
Walter wrote:

 Your use of templates to do varargs is cool. I made a couple of fixes, and
 the result is std.stdarg! It'll go out in the next release.

Cool! Could I suggest a name of "std.vararg"? (Or perhaps we could go a step farther and call it "std.stdstdarg?")
 
 -------------------------------------------------
 /*
  * Placed in public domain.
  * Written by Hauke Duden and Walter Bright
  */
 
 module std.stdarg;
 
 typedef void* va_list;
 
 template va_start(T)
 {
     void va_start(out va_list ap, inout T parmn)
     {
  ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) &
 ~(int.sizeof - 1)));
     }
 }
 
 template va_arg(T)
 {
     T va_arg(inout va_list ap)
     {
  T arg = *cast(T*)ap;
  ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) &
 ~(int.sizeof - 1)));
  return arg;
     }
 }
 
 void va_end(va_list ap)
 {
 }
 ------------------------------------------------------------------
 Here's a little test program to show how to use it:
 
 ------------------------------------------------------------------
 import std.stdarg;
 
 int foo(char *x, ...)
 {
     va_list ap;
 
     va_start!(typeof(x))(ap, x);
     printf("&x = %p, ap = %p\n", &x, ap);
 
     int i;
     i = va_arg!(typeof(i))(ap);
     printf("i = %d\n", i);
 
     long l;
     l = va_arg!(typeof(l))(ap);
     printf("l = %lld\n", l);
 
     uint k;
     k = va_arg!(typeof(k))(ap);
     printf("k = %u\n", k);
 
     va_end(ap);
 
     return i + l + k;
 }
 
 void main()
 {
     int j;
 
     j = foo("hello", 3, 23L, 4);
     printf("j = %d\n", j);
     assert(j == 30);
 }
 ------------------------------------------------------

-- Justin http://jcc_7.tripod.com/d/
May 02 2004
parent "Walter" <newshound digitalmars.com> writes:
On second thought, it should be std.c.stdarg, since it mirrors the C
stdarg.h.

"J C Calvarese" <jcc7 cox.net> wrote in message
news:c73c0e$1tj1$2 digitaldaemon.com...
 Walter wrote:

 Your use of templates to do varargs is cool. I made a couple of fixes,


 the result is std.stdarg! It'll go out in the next release.

Cool! Could I suggest a name of "std.vararg"? (Or perhaps we could go a step farther and call it "std.stdstdarg?")
 -------------------------------------------------
 /*
  * Placed in public domain.
  * Written by Hauke Duden and Walter Bright
  */

 module std.stdarg;

 typedef void* va_list;

 template va_start(T)
 {
     void va_start(out va_list ap, inout T parmn)
     {
  ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) &
 ~(int.sizeof - 1)));
     }
 }

 template va_arg(T)
 {
     T va_arg(inout va_list ap)
     {
  T arg = *cast(T*)ap;
  ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) &
 ~(int.sizeof - 1)));
  return arg;
     }
 }

 void va_end(va_list ap)
 {
 }
 ------------------------------------------------------------------
 Here's a little test program to show how to use it:

 ------------------------------------------------------------------
 import std.stdarg;

 int foo(char *x, ...)
 {
     va_list ap;

     va_start!(typeof(x))(ap, x);
     printf("&x = %p, ap = %p\n", &x, ap);

     int i;
     i = va_arg!(typeof(i))(ap);
     printf("i = %d\n", i);

     long l;
     l = va_arg!(typeof(l))(ap);
     printf("l = %lld\n", l);

     uint k;
     k = va_arg!(typeof(k))(ap);
     printf("k = %u\n", k);

     va_end(ap);

     return i + l + k;
 }

 void main()
 {
     int j;

     j = foo("hello", 3, 23L, 4);
     printf("j = %d\n", j);
     assert(j == 30);
 }
 ------------------------------------------------------

-- Justin http://jcc_7.tripod.com/d/

May 02 2004
prev sibling next sibling parent "Andrew Edwards" <edwardsac spamfreeusa.com> writes:
"Walter" <newshound digitalmars.com> wrote in message
news:c73b94$1svo$1 digitaldaemon.com...
 Your use of templates to do varargs is cool. I made a couple of fixes, and
 the result is std.stdarg! It'll go out in the next release.

Awesome! Now there's only one thing I'd like to bother you with: can we please have types as parameters for switch/case statements? i.e. type T; switch(typeof(T)) { case (int): ... case (double): ... case (char[]): ... } Thanks, Andrew
 -------------------------------------------------

 ------------------------------------------------------------------
 Here's a little test program to show how to use it:

 ------------------------------------------------------------------

 ------------------------------------------------------

May 02 2004
prev sibling parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Walter wrote:
 Your use of templates to do varargs is cool. I made a couple of fixes, and
 the result is std.stdarg! It'll go out in the next release.

Thanks! I thought it was obvious, but apparently it was not ;). But: is there a real reason why there even is a va_end? Since it is empty I see no need to burden the user with calling it. I'd also suggest to modify va_start like this: template va_start(T) { va_list va_start(inout T parmn) { return cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1))); } } I.e. return the va_list instead of filling an out parameter. That way the user can write "va_list args=va_start" instead of having to make two lines of it. Hauke
May 02 2004
parent "Walter" <newshound digitalmars.com> writes:
"Hauke Duden" <H.NS.Duden gmx.net> wrote in message
news:c73f7f$24jc$1 digitaldaemon.com...
 Walter wrote:
 Your use of templates to do varargs is cool. I made a couple of fixes,


 the result is std.stdarg! It'll go out in the next release.


Nothing is ever as simple as it seems. I goofed up my first version, too.
 But: is there a real reason why there even is a va_end? Since it is
 empty I see no need to burden the user with calling it.

Some CPU architectures require it, and have a non-empty va_end(), which works like a destructor. To write portable code, it'll need to be there.
 I'd also suggest
 to modify va_start like this:

 template va_start(T)
 {
      va_list va_start(inout T parmn)
      {
   return cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) &
 ~(int.sizeof - 1)));
      }
 }

 I.e. return the va_list instead of filling an out parameter. That way
 the user can write "va_list args=va_start" instead of having to make two
 lines of it.

I understand, but upon second thought I want to make this a simple analog of C's <stdarg.h>, and move it into std.c.stdarg. The va_end() suggests that a D-ish version would make use of an auto class for robust cleanup, and so I want to leave the door open for this better design, which would also incorporate your suggestion.
May 02 2004