Re: parsing variable arg lists via va_list pointers (any gurus here?)

Discussion in 'C Programming' started by Tomás Ó hÉilidhe, Jun 3, 2008.

  1. On Jun 3, 3:23 am, Jesse Ziser <> wrote:

    > ANSI says that when you pass a va_list object to
    > a function and call va_arg() on it within that function, the value of
    > the va_list object is undefined upon return.



    The relevant paragraph from the Standard is:

    ---- Begin Quote ----
    The type declared is va_list
    which is an object type suitable for holding information needed by the
    macros
    va_start, va_arg, va_end, and va_copy. If access to the varying
    arguments is
    desired, the called function shall declare an object (generally
    referred to as ap in this
    subclause) having type va_list. The object ap may be passed as an
    argument to
    another function; if that function invokes the va_arg macro with
    parameter ap, the
    value of ap in the calling function is indeterminate and shall be
    passed to the va_end
    macro prior to any further reference to ap.
    ---- End Quote ----

    At first reading, I thought this was just saying the following:
    * C passes arguments by value, i.e. the object in the calling
    function remains unchanged
    * The va_* macros alter their va_list argument
    * You can only use the most up-to-date va_list, you can't use an
    old out-of-date one


    >  Behold:
    >
    > void parse_half_of_arg_list( va_list args )
    > {
    >    ...
    >    foo_t x = va_arg( args, foo_t );
    >    bar_t y = va_arg( args, bar_t );
    >    ...
    >
    > }
    >
    > void superfunc( int a, ... )
    > {
    >    va_list args;
    >
    >    va_start( args, a );
    >
    >    parse_half_of_arg_list( args );
    >    /* Uh-oh!  ANSI says args is undefined now,
    >       but there's still more to parse */
    >    parse_half_of_arg_list( args );
    >
    >    va_end( args );
    >
    > }



    The va_list object in "main" remains unchanged, therefore it is no
    longer "up to date" when you go to try use another va_* macro on it.


    > So, I reasoned, why not pass a va_list * instead of a va_list?  Surely
    > that can't do any harm... I mean, since va_list is a data type, it
    > should be possible to create a pointer to it, and *(&x) should be the
    > same as x for any named type and for any operations, right?  Lo:
    >
    > void parse_half_of_arg_list( va_list *args )
    > {
    >    ...
    >    foo_t x = va_arg( *args, foo_t );
    >    bar_t y = va_arg( *args, bar_t );
    >    ...
    >
    > }
    >
    > void superfunc( int a, ... )
    > {
    >    va_list args;
    >
    >    va_start( args, a );
    >
    >    parse_half_of_arg_list( &args );
    >    parse_half_of_arg_list( &args );
    >
    >    va_end( args );
    >
    > }
    >
    > I haven't been able to find anything in any standard that explicitly
    > allows or prohibits this, but there aren't many ways I can think of that
    > some devious library author could screw this up.  The thing is, this
    > code will exist for a long time and will quite possibly need to run
    > under every semi-major system and C compiler that will come into
    > existence in the next 20 years.  As of right now it will need to
    > immediately work on Sun, Mac, Cygwin, and Linux and compile under gcc,
    > pgcc, and icc.



    I find the original paragraph from the Standard to be very strange. I
    don't see why it went to the bother of mentioning calling and called
    functions when it just could have said "the va_list must always be up-
    to-date". This kind of leads me to believe that maybe there's some
    other requirement than the va_list being up to date... maybe something
    to do with the stack.


    > So, I guess the gist is that I want to do something really weird but I
    > want it to be really portable, and I'm afraid that might be an
    > impossibility.  Not being able to do this would mean I'd have to use a
    > bunch of structs or arrays with void pointers everywhere, which is a
    > considerable burden as this function will be called very frequently.
    >
    > I am well aware that this is a really bizarre thing to have to do.
    >
    > Please let me know if you know a system that breaks this, or if you have
    > good cause to believe that this will always work.
    >
    > Thanks in advance.



    Wait and see what others have to say.
     
    Tomás Ó hÉilidhe, Jun 3, 2008
    #1
    1. Advertising

  2. On Jun 3, 4:28 am, Tomás Ó hÉilidhe <> wrote:

    > I find the original paragraph from the Standard to be very strange. I
    > don't see why it went to the bother of mentioning calling and called
    > functions when it just could have said "the va_list must always be up-
    > to-date". This kind of leads me to believe that maybe there's some
    > other requirement than the va_list being up to date... maybe something
    > to do with the stack.


    There are some interesting architectures out there that do interesting
    things in the va_arg macros. Sparc machines come to mind, or Itanium.
    There may be compiler support needed (even the x86-64 ABI looks like a
    major pain).

    Also note that va_list could be defined either as an array or as a
    struct. All the macros will work if you use them as the C Standard
    says, but the effect of applying an address operator or having a
    pointer to a va_list could be very different in both cases.
     
    christian.bau, Jun 3, 2008
    #2
    1. Advertising

  3. Tomás Ó hÉilidhe

    Bartc Guest

    "Richard Heathfield" <> wrote in message
    news:...
    > Jesse Ziser said:
    >
    > <snip>
    >>
    >> Could you explain how address operators and pointers could behave
    >> differently depending on whether va_list is a struct or array type? To
    >> my knowledge, if stdarg.h contains either of these:
    >>
    >> typedef weird_t va_list[42];
    >> typedef struct weird va_list;
    >>
    >> And I declare:
    >>
    >> va_list args;
    >>
    >> Then, in either case, *(&args) will still behave exactly the same as
    >> args. Is there some case I'm not thinking of in which this is not true?

    >
    > No. * and & "cancel".


    So in other words, *(&args) is the same as args like he said?

    (There is a slight difference: args has to be an lvalue for *(&args) to
    work, so *(&1234) and 1234 are not the same since the former won't
    compile -- assuming a suitable context.)

    --
    Bartc
     
    Bartc, Jun 4, 2008
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jon

    Modifying an arg of va_list

    Jon, Jul 14, 2005, in forum: C Programming
    Replies:
    7
    Views:
    607
  2. n00m
    Replies:
    5
    Views:
    413
  3. Chris Dollin
    Replies:
    4
    Views:
    290
    Chris Dollin
    Jun 4, 2008
  4. Amandil
    Replies:
    1
    Views:
    931
    Peter Nilsson
    Jun 4, 2008
  5. Replies:
    7
    Views:
    204
Loading...

Share This Page