Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #16489 > unrolled thread
| Started by | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| First post | 2012-01-31 09:12 -0500 |
| Last post | 2012-01-31 11:33 -0800 |
| Articles | 16 — 4 participants |
Back to article view | Back to comp.lang.c
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
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-01-31 09:12 -0500 |
| Subject | va_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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-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]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-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]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2012-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-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]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2012-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]
| From | Harald van Dijk <haraldvdijk@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Shao Miller <sha0.miller@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Harald van Dijk <haraldvdijk@gmail.com> |
|---|---|
| Date | 2012-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]
| From | Harald van Dijk <haraldvdijk@gmail.com> |
|---|---|
| Date | 2012-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