Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #16489 > unrolled thread

va_args Conformance

Started byShao Miller <sha0.miller@gmail.com>
First post2012-01-31 09:12 -0500
Last post2012-01-31 11:33 -0800
Articles 16 — 4 participants

Back to article view | Back to comp.lang.c


Contents

  va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 09:12 -0500
    Re: va_args Conformance Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-01-31 14:50 +0000
      Re: va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 10:11 -0500
        Re: va_args Conformance Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-01-31 17:19 +0000
          Re: va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 12:31 -0500
            Re: va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 12:34 -0500
              Re: va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 12:40 -0500
            Re: va_args Conformance Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-01-31 17:52 +0000
      Re: va_args Conformance James Kuyper <jameskuyper@verizon.net> - 2012-01-31 11:27 -0500
        Re: va_args Conformance Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-01-31 16:53 +0000
          Re: va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 12:09 -0500
          Re: va_args Conformance James Kuyper <jameskuyper@verizon.net> - 2012-01-31 12:15 -0500
    Re: va_args Conformance Harald van Dijk <haraldvdijk@gmail.com> - 2012-01-31 09:46 -0800
      Re: va_args Conformance Shao Miller <sha0.miller@gmail.com> - 2012-01-31 13:45 -0500
        Re: va_args Conformance Harald van Dijk <haraldvdijk@gmail.com> - 2012-01-31 11:28 -0800
        Re: va_args Conformance Harald van Dijk <haraldvdijk@gmail.com> - 2012-01-31 11:33 -0800

#16489 — va_args Conformance

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 09:12 -0500
Subjectva_args Conformance
Message-ID<jg8ssi$5ea$1@dont-email.me>
If the following program strictly conforming?

   #include <stddef.h>
   #include <stdarg.h>

   static void test(int, ...);

   int main(void) {
       test(0, 42);

       return 0;
     }

   static void test(int x, ...) {
       typedef unsigned char one_char[1];
       /* Valid declaration on the next line */
       one_char * unused;
       va_list varargs;
       unsigned char * byte;

       va_start(varargs, x);
       if (x)
           byte = va_arg(varargs, one_char);
       va_end(varargs);

       return;
     }

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [next] | [standalone]


#16493

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-01-31 14:50 +0000
Message-ID<0.974e5b6a5e777ba20127.20120131145047GMT.8739awq62g.fsf@bsb.me.uk>
In reply to#16489
Shao Miller <sha0.miller@gmail.com> writes:

> If the following program strictly conforming?
>
>   #include <stddef.h>
>   #include <stdarg.h>
>
>   static void test(int, ...);
>
>   int main(void) {
>       test(0, 42);
>
>       return 0;
>     }
>
>   static void test(int x, ...) {
>       typedef unsigned char one_char[1];
>       /* Valid declaration on the next line */
>       one_char * unused;
>       va_list varargs;
>       unsigned char * byte;
>
>       va_start(varargs, x);
>       if (x)
>           byte = va_arg(varargs, one_char);
>       va_end(varargs);
>
>       return;
>     }

It looks fine to me.  Does some implementation reject it?

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#16496

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 10:11 -0500
Message-ID<jg90bd$qg4$1@dont-email.me>
In reply to#16493
On 1/31/2012 09:50, Ben Bacarisse wrote:
> Shao Miller<sha0.miller@gmail.com>  writes:
>
>> If the following program strictly conforming?
>>
>>    #include<stddef.h>
>>    #include<stdarg.h>
>>
>>    static void test(int, ...);
>>
>>    int main(void) {
>>        test(0, 42);
>>
>>        return 0;
>>      }
>>
>>    static void test(int x, ...) {
>>        typedef unsigned char one_char[1];
>>        /* Valid declaration on the next line */
>>        one_char * unused;
>>        va_list varargs;
>>        unsigned char * byte;
>>
>>        va_start(varargs, x);
>>        if (x)
>>            byte = va_arg(varargs, one_char);
>>        va_end(varargs);
>>
>>        return;
>>      }
>
> It looks fine to me.  Does some implementation reject it?
>

Yes.  At least two of them, and in different ways that I didn't quite 
expect.

GCC 4.3.3 says:

   test.c: In function 'test':
   test.c:21: error: invalid use of non-lvalue array

Where 'va_arg' expands to '__builtin_va_arg'.

clang 2.9 says:

   test.c:21:16: error: assigning to 'unsigned char *' from incompatible 
type 'one_char' (aka 'unsigned char [1]')
             byte = va_arg(varargs, one_char);
                  ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
   1 error generated.

Where once again, 'va_arg' expands to '__builtin_va_arg'.

My reading of N1256's 7.15.1.1 has me pondering these.

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [prev] | [next] | [standalone]


#16506

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-01-31 17:19 +0000
Message-ID<0.be3f00a68344a53a33db.20120131171954GMT.87ipjrpz5x.fsf@bsb.me.uk>
In reply to#16496
Shao Miller <sha0.miller@gmail.com> writes:

> On 1/31/2012 09:50, Ben Bacarisse wrote:
>> Shao Miller<sha0.miller@gmail.com>  writes:
>>
>>> If the following program strictly conforming?
>>>
>>>    #include<stddef.h>
>>>    #include<stdarg.h>
>>>
>>>    static void test(int, ...);
>>>
>>>    int main(void) {
>>>        test(0, 42);
>>>
>>>        return 0;
>>>      }
>>>
>>>    static void test(int x, ...) {
>>>        typedef unsigned char one_char[1];
>>>        /* Valid declaration on the next line */
>>>        one_char * unused;
>>>        va_list varargs;
>>>        unsigned char * byte;
>>>
>>>        va_start(varargs, x);
>>>        if (x)
>>>            byte = va_arg(varargs, one_char);
>>>        va_end(varargs);
>>>
>>>        return;
>>>      }
>>
>> It looks fine to me.  Does some implementation reject it?
>>
>
> Yes.  At least two of them, and in different ways that I didn't quite
> expect.
>
> GCC 4.3.3 says:
>
>   test.c: In function 'test':
>   test.c:21: error: invalid use of non-lvalue array
>
> Where 'va_arg' expands to '__builtin_va_arg'.

gcc 4.6.1 is happy with it...

> clang 2.9 says:
>
>   test.c:21:16: error: assigning to 'unsigned char *' from
> incompatible type 'one_char' (aka 'unsigned char [1]')
>             byte = va_arg(varargs, one_char);
>                  ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
>   1 error generated.

... and my clang version 2.9 (tags/RELEASE_29/final) is also happy with
it.

> Where once again, 'va_arg' expands to '__builtin_va_arg'.
>
> My reading of N1256's 7.15.1.1 has me pondering these.

It seems OK to me.  va_arg(varargs, one_char) must be an expression of
type one_char.  An expression with type "array of T" gets converted to
one of type "pointer to T" so the assignment should type-check.  (You
can't execute the line without UB, but presumably that's why you put
the if (x) check there.)

I was briefly concerned that maybe the array-to-pointer conversion might
only apply to lvalue expressions, but it does not -- it applies to any
expression with an array type (other than a string literal or one that
is the operand of sizeof or unary &).
 
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#16509

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 12:31 -0500
Message-ID<jg98gr$efk$1@dont-email.me>
In reply to#16506
On 1/31/2012 12:19, Ben Bacarisse wrote:
> Shao Miller<sha0.miller@gmail.com>  writes:
>
>> On 1/31/2012 09:50, Ben Bacarisse wrote:
>>> Shao Miller<sha0.miller@gmail.com>   writes:
>>>
>>>> If the following program strictly conforming?
>>>>
>>>>     #include<stddef.h>
>>>>     #include<stdarg.h>
>>>>
>>>>     static void test(int, ...);
>>>>
>>>>     int main(void) {
>>>>         test(0, 42);
>>>>
>>>>         return 0;
>>>>       }
>>>>
>>>>     static void test(int x, ...) {
>>>>         typedef unsigned char one_char[1];
>>>>         /* Valid declaration on the next line */
>>>>         one_char * unused;
>>>>         va_list varargs;
>>>>         unsigned char * byte;
>>>>
>>>>         va_start(varargs, x);
>>>>         if (x)
>>>>             byte = va_arg(varargs, one_char);
>>>>         va_end(varargs);
>>>>
>>>>         return;
>>>>       }
>>>
>>> It looks fine to me.  Does some implementation reject it?
>>>
>>
>> Yes.  At least two of them, and in different ways that I didn't quite
>> expect.
>>
>> GCC 4.3.3 says:
>>
>>    test.c: In function 'test':
>>    test.c:21: error: invalid use of non-lvalue array
>>
>> Where 'va_arg' expands to '__builtin_va_arg'.
>
> gcc 4.6.1 is happy with it...
>

Aha.  Thanks a lot for checking that!

>> clang 2.9 says:
>>
>>    test.c:21:16: error: assigning to 'unsigned char *' from
>> incompatible type 'one_char' (aka 'unsigned char [1]')
>>              byte = va_arg(varargs, one_char);
>>                   ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
>>    1 error generated.
>
> ... and my clang version 2.9 (tags/RELEASE_29/final) is also happy with
> it.
>

That's odd.  I was also using "tags/RELEASE_29/final".  I was using 
'-ansi -pedantic' as well, so maybe there's a C90 vs. C99 difference in 
treatment?

>> Where once again, 'va_arg' expands to '__builtin_va_arg'.
>>
>> My reading of N1256's 7.15.1.1 has me pondering these.
>
> It seems OK to me.  va_arg(varargs, one_char) must be an expression of
> type one_char.  An expression with type "array of T" gets converted to
> one of type "pointer to T" so the assignment should type-check.  (You
> can't execute the line without UB, but presumably that's why you put
> the if (x) check there.)
>

I had the same reasoning, so thank you very much for that.  Yes, I 
believe the undefined behaviour would be from the 'va_arg' result not 
being addressable, so the address of the first element would be 
undefined and hence the would-be-resulting pointer value.

Beyond all of that business, I don't know of a way to pass an array to 
any function, so the 'one_char' type could never be compatible with any 
parameter.  But that wasn't the point of the original question, of course.

> I was briefly concerned that maybe the array-to-pointer conversion might
> only apply to lvalue expressions, but it does not -- it applies to any
> expression with an array type (other than a string literal or one that
> is the operand of sizeof or unary&).
>

I had some moments where I shared this same concern and drew the same 
conclusion.  This seems to be related to something like:

   typedef unsigned char one_char[1];
   register one_char foo;

where there are now restrictions on the use of 'foo'; 'sizeof' and 
'_AlignOf' only, presumably.

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [prev] | [next] | [standalone]


#16510

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 12:34 -0500
Message-ID<jg98m8$efk$2@dont-email.me>
In reply to#16509
On 1/31/2012 12:31, Shao Miller wrote:
>
> I had some moments where I shared this same concern and drew the same
> conclusion. This seems to be related to something like:
>
> typedef unsigned char one_char[1];
> register one_char foo;
>
> where there are now restrictions on the use of 'foo'; 'sizeof' and
> '_AlignOf' only, presumably.
>

Uh.  I meant 'alignof'.  Oops.

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [prev] | [next] | [standalone]


#16514

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 12:40 -0500
Message-ID<jg991v$hak$1@dont-email.me>
In reply to#16510
On 1/31/2012 12:34, Shao Miller wrote:
> On 1/31/2012 12:31, Shao Miller wrote:
>>
>> I had some moments where I shared this same concern and drew the same
>> conclusion. This seems to be related to something like:
>>
>> typedef unsigned char one_char[1];
>> register one_char foo;
>>
>> where there are now restrictions on the use of 'foo'; 'sizeof' and
>> '_AlignOf' only, presumably.
>>
>
> Uh. I meant 'alignof'. Oops.
>

And I'm wrong, anyway.  [Albeit outdated] N1494 doesn't have 'alignof' 
applying to identifiers.  I forgot about the gripe I had about that in 
comp.std.c some time ago.

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [prev] | [next] | [standalone]


#16519

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-01-31 17:52 +0000
Message-ID<0.8c678c7e5bc519c9354c.20120131175214GMT.877h07pxo1.fsf@bsb.me.uk>
In reply to#16509
Shao Miller <sha0.miller@gmail.com> writes:

> On 1/31/2012 12:19, Ben Bacarisse wrote:
>> Shao Miller<sha0.miller@gmail.com>  writes:
<snip>
>>> clang 2.9 says:
>>>
>>>    test.c:21:16: error: assigning to 'unsigned char *' from
>>> incompatible type 'one_char' (aka 'unsigned char [1]')
>>>              byte = va_arg(varargs, one_char);
>>>                   ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
>>>    1 error generated.
>>
>> ... and my clang version 2.9 (tags/RELEASE_29/final) is also happy with
>> it.
>
> That's odd.  I was also using "tags/RELEASE_29/final".  I was using
> -ansi -pedantic' as well, so maybe there's a C90 vs. C99 difference in
> treatment?

So it would seem.  Error with -std=C90, fine with -C99.  The C90 wording
is:

  "The va_arg macro expands to an expression that has the type and value
  of the next argument in the call."

which I find very strange!

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#16500

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-01-31 11:27 -0500
Message-ID<4F281677.3090906@verizon.net>
In reply to#16493
On 01/31/2012 09:50 AM, Ben Bacarisse wrote:
> Shao Miller <sha0.miller@gmail.com> writes:
> 
>> If the following program strictly conforming?
>>
>>   #include <stddef.h>
>>   #include <stdarg.h>
>>
>>   static void test(int, ...);
>>
>>   int main(void) {
>>       test(0, 42);
>>
>>       return 0;
>>     }
>>
>>   static void test(int x, ...) {
>>       typedef unsigned char one_char[1];
>>       /* Valid declaration on the next line */
>>       one_char * unused;
>>       va_list varargs;
>>       unsigned char * byte;
>>
>>       va_start(varargs, x);
>>       if (x)
>>           byte = va_arg(varargs, one_char);
>>       va_end(varargs);
>>
>>       return;
>>     }
> 
> It looks fine to me.  Does some implementation reject it?

The second argument of his call to test() has a type of int. He calls
va_arg() with a type of one_char, which is a typedef for unsigned char.
"if type is not compatible with the type of the actual next argument (as
promoted according to the default argument promotions), the behavior is
undefined ..." (7.15.1.1p2). The promoted type of "int" is "int".
"unsigned char" is not compatible with "int". That clause has some
exceptions, but none of them are applicable.

[toc] | [prev] | [next] | [standalone]


#16503

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2012-01-31 16:53 +0000
Message-ID<0.32a50875bd525ebe1f4b.20120131165310GMT.87pqdzq0eh.fsf@bsb.me.uk>
In reply to#16500
James Kuyper <jameskuyper@verizon.net> writes:

> On 01/31/2012 09:50 AM, Ben Bacarisse wrote:
>> Shao Miller <sha0.miller@gmail.com> writes:
>> 
>>> If the following program strictly conforming?
>>>
>>>   #include <stddef.h>
>>>   #include <stdarg.h>
>>>
>>>   static void test(int, ...);
>>>
>>>   int main(void) {
>>>       test(0, 42);
>>>
>>>       return 0;
>>>     }
>>>
>>>   static void test(int x, ...) {
>>>       typedef unsigned char one_char[1];
>>>       /* Valid declaration on the next line */
>>>       one_char * unused;
>>>       va_list varargs;
>>>       unsigned char * byte;
>>>
>>>       va_start(varargs, x);
>>>       if (x)
>>>           byte = va_arg(varargs, one_char);
>>>       va_end(varargs);
>>>
>>>       return;
>>>     }
>> 
>> It looks fine to me.  Does some implementation reject it?
>
> The second argument of his call to test() has a type of int. He calls
> va_arg() with a type of one_char, which is a typedef for unsigned
> char.

I though his code did not do this.  Was that not the point of the
if (x) with x == 0?

> "if type is not compatible with the type of the actual next argument (as
> promoted according to the default argument promotions), the behavior is
> undefined ..." (7.15.1.1p2). The promoted type of "int" is "int".
> "unsigned char" is not compatible with "int". That clause has some
> exceptions, but none of them are applicable.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#16504

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 12:09 -0500
Message-ID<jg9789$4uq$1@dont-email.me>
In reply to#16503
On 1/31/2012 11:53, Ben Bacarisse wrote:
> James Kuyper<jameskuyper@verizon.net>  writes:
>
>> On 01/31/2012 09:50 AM, Ben Bacarisse wrote:
>>> Shao Miller<sha0.miller@gmail.com>  writes:
>>>
>>>> If the following program strictly conforming?
>>>>
>>>>    #include<stddef.h>
>>>>    #include<stdarg.h>
>>>>
>>>>    static void test(int, ...);
>>>>
>>>>    int main(void) {
>>>>        test(0, 42);
>>>>
>>>>        return 0;
>>>>      }
>>>>
>>>>    static void test(int x, ...) {
>>>>        typedef unsigned char one_char[1];
>>>>        /* Valid declaration on the next line */
>>>>        one_char * unused;
>>>>        va_list varargs;
>>>>        unsigned char * byte;
>>>>
>>>>        va_start(varargs, x);
>>>>        if (x)
>>>>            byte = va_arg(varargs, one_char);
>>>>        va_end(varargs);
>>>>
>>>>        return;
>>>>      }
>>>
>>> It looks fine to me.  Does some implementation reject it?
>>
>> The second argument of his call to test() has a type of int. He calls
>> va_arg() with a type of one_char, which is a typedef for unsigned
>> char.
>
> I though his code did not do this.  Was that not the point of the
> if (x) with x == 0?
>

Yes, that was the point, to keep the test-case fairly simple.  I gather 
that 'printf' [theoretically] uses the passed format string to determine 
what kind of 'va_arg' to do each other additional parameter in a loosely 
similar fashion, for example.

>> "if type is not compatible with the type of the actual next argument (as
>> promoted according to the default argument promotions), the behavior is
>> undefined ..." (7.15.1.1p2). The promoted type of "int" is "int".
>> "unsigned char" is not compatible with "int". That clause has some
>> exceptions, but none of them are applicable.
>

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [prev] | [next] | [standalone]


#16505

FromJames Kuyper <jameskuyper@verizon.net>
Date2012-01-31 12:15 -0500
Message-ID<4F2821C4.5020809@verizon.net>
In reply to#16503
On 01/31/2012 11:53 AM, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
> 
>> On 01/31/2012 09:50 AM, Ben Bacarisse wrote:
>>> Shao Miller <sha0.miller@gmail.com> writes:
>>>
>>>> If the following program strictly conforming?
>>>>
>>>>   #include <stddef.h>
>>>>   #include <stdarg.h>
>>>>
>>>>   static void test(int, ...);
>>>>
>>>>   int main(void) {
>>>>       test(0, 42);
>>>>
>>>>       return 0;
>>>>     }
>>>>
>>>>   static void test(int x, ...) {
>>>>       typedef unsigned char one_char[1];
>>>>       /* Valid declaration on the next line */
>>>>       one_char * unused;
>>>>       va_list varargs;
>>>>       unsigned char * byte;
>>>>
>>>>       va_start(varargs, x);
>>>>       if (x)
>>>>           byte = va_arg(varargs, one_char);
>>>>       va_end(varargs);
>>>>
>>>>       return;
>>>>     }
>>>
>>> It looks fine to me.  Does some implementation reject it?
>>
>> The second argument of his call to test() has a type of int. He calls
>> va_arg() with a type of one_char, which is a typedef for unsigned
>> char.
> 
> I though his code did not do this.  Was that not the point of the
> if (x) with x == 0?

You're right - I didn't pay attention to that. Sorry!

[toc] | [prev] | [next] | [standalone]


#16516

FromHarald van Dijk <haraldvdijk@gmail.com>
Date2012-01-31 09:46 -0800
Message-ID<93f0c4d6-7c90-492d-aced-062800e8e27f@y10g2000vbn.googlegroups.com>
In reply to#16489
On Jan 31, 3:12 pm, Shao Miller <sha0.mil...@gmail.com> wrote:
> If the following program strictly conforming?
>
>    #include <stddef.h>
>    #include <stdarg.h>
>
>    static void test(int, ...);
>
>    int main(void) {
>        test(0, 42);
>
>        return 0;
>      }
>
>    static void test(int x, ...) {
>        typedef unsigned char one_char[1];
>        /* Valid declaration on the next line */
>        one_char * unused;
>        va_list varargs;
>        unsigned char * byte;
>
>        va_start(varargs, x);
>        if (x)
>            byte = va_arg(varargs, one_char);

In C90, this is invalid. As your compilers' error messages state, the
standard does not require va_arg's result to be an lvalue, and a non-
lvalue array cannot be used in any way except to discard it, to take
its size, or to uselessly pass it to another variadic function. In
particular, it cannot be converted to a pointer, and its members
cannot be accessed.

In C99 (and presumably C11), this use of va_arg unconditionally
invokes undefined behaviour: there is no longer any way to pass an
array to a variadic function without it getting converted to a pointer
to its first element. A line that unconditionally invokes undefined
behaviour at runtime is technically allowed in a strictly conforming
program if the line is never executed, but this would not be the first
example where compilers divert from the standard in that regard.

>        va_end(varargs);
>
>        return;
>      }

[toc] | [prev] | [next] | [standalone]


#16522

FromShao Miller <sha0.miller@gmail.com>
Date2012-01-31 13:45 -0500
Message-ID<jg9csa$cca$1@dont-email.me>
In reply to#16516
On 1/31/2012 12:46, Harald van Dijk wrote:
> On Jan 31, 3:12 pm, Shao Miller<sha0.mil...@gmail.com>  wrote:
>> If the following program strictly conforming?
>>
>>     #include<stddef.h>
>>     #include<stdarg.h>
>>
>>     static void test(int, ...);
>>
>>     int main(void) {
>>         test(0, 42);
>>
>>         return 0;
>>       }
>>
>>     static void test(int x, ...) {
>>         typedef unsigned char one_char[1];
>>         /* Valid declaration on the next line */
>>         one_char * unused;
>>         va_list varargs;
>>         unsigned char * byte;
>>
>>         va_start(varargs, x);
>>         if (x)
>>             byte = va_arg(varargs, one_char);
>
> In C90, this is invalid. As your compilers' error messages state, the
> standard does not require va_arg's result to be an lvalue, and a non-
> lvalue array cannot be used in any way except to discard it, to take
> its size, or to uselessly pass it to another variadic function. In
> particular, it cannot be converted to a pointer, and its members
> cannot be accessed.
>

Aha!  Thanks very much.  Indeed, the result is a "value" rather than 
designating an "object."

That such a value can be passed to another function is interesting, 
though...  I suppose it could be passed to a non-variadic function whose 
parameters aren't specified, too.

> In C99 (and presumably C11), this use of va_arg unconditionally
> invokes undefined behaviour: there is no longer any way to pass an
> array to a variadic function without it getting converted to a pointer
> to its first element.

Out of curiosity, how could you pass an array pre-C99?  Or do you mean 
for the strict case where the expression is an array "value" without 
being an lvalue, that you described above?

The program doesn't attempt to pass an array to the 'test' function, by 
the way.  So I think by "this use," you were referring to a construct 
which didn't appear in the program, but which might be associated with 
it.  Or did you really mean a construct in the program?

> A line that unconditionally invokes undefined
> behaviour at runtime is technically allowed in a strictly conforming
> program if the line is never executed, but this would not be the first
> example where compilers divert from the standard in that regard.
>

I see.  Well thanks again!

-- 
"The stationery store has moved.  Aaargh!"

[toc] | [prev] | [next] | [standalone]


#16523

FromHarald van Dijk <haraldvdijk@gmail.com>
Date2012-01-31 11:28 -0800
Message-ID<869b6f8d-71a8-4516-9256-f4576af16fd8@r12g2000yqh.googlegroups.com>
In reply to#16522
On Jan 31, 7:45 pm, Shao Miller <sha0.mil...@gmail.com> wrote:
> On 1/31/2012 12:46, Harald van Dijk wrote:
> > In C99 (and presumably C11), this use of va_arg unconditionally
> > invokes undefined behaviour: there is no longer any way to pass an
> > array to a variadic function without it getting converted to a pointer
> > to its first element.
>
> Out of curiosity, how could you pass an array pre-C99?  Or do you mean
> for the strict case where the expression is an array "value" without
> being an lvalue, that you described above?

Right, this is a program that I believe to strictly conform to the C90
standard:

#include <stdarg.h>
typedef char array[10];
struct S { array array; };
struct S foo(void) { static struct S s; return s; }
int bar(int x, ...)
{
  int result;
  va_list ap;
  va_start(ap, x);
  va_arg(ap, array);
  result = va_arg(ap, int);
  va_end(ap);
  return result;
}
int main(void)
{
  return bar(0, foo().array, 0);
}

It's useless, but it's valid, and C90's va_arg is (strictly speaking:
for practical purposes nobody really cares) required to skip over the
array to correctly read the next passed argument.

> The program doesn't attempt to pass an array to the 'test' function, by
> the way.  So I think by "this use," you were referring to a construct
> which didn't appear in the program, but which might be associated with
> it.  Or did you really mean a construct in the program?

I meant the use of va_arg: if its second argument has array type, it
cannot possibly be compatible with the type of the passed argument in
C99, no matter how you call the function. If you pass an array, even
an array rvalue, it gets converted to a pointer, so va_arg's second
argument should be a pointer type.

[toc] | [prev] | [next] | [standalone]


#16524

FromHarald van Dijk <haraldvdijk@gmail.com>
Date2012-01-31 11:33 -0800
Message-ID<d7322bc2-9c61-423e-a8f6-3d20d3b4b845@hb4g2000vbb.googlegroups.com>
In reply to#16522
On Jan 31, 7:45 pm, Shao Miller <sha0.mil...@gmail.com> wrote:
> On 1/31/2012 12:46, Harald van Dijk wrote:
> > In C90, this is invalid. As your compilers' error messages state, the
> > standard does not require va_arg's result to be an lvalue, and a non-
> > lvalue array cannot be used in any way except to discard it, to take
> > its size, or to uselessly pass it to another variadic function. In
> > particular, it cannot be converted to a pointer, and its members
> > cannot be accessed.
>
> Aha!  Thanks very much.  Indeed, the result is a "value" rather than
> designating an "object."
>
> That such a value can be passed to another function is interesting,
> though...

But be careful: the standard doesn't require va_arg's result to be an
lvalue, but does allow it. If it is an lvalue, then it will get
converted to a pointer if you pass it on to another function!

> I suppose it could be passed to a non-variadic function whose
> parameters aren't specified, too.

Perhaps, but a non-variadic function cannot have a definition allowing
arguments of array type (parameters of array type are converted to
pointers too), so again, the behaviour would again always be
undefined, no matter how the function is defined.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web