Path: csiph.com!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Is this valid C? Date: Sun, 19 Feb 2017 12:04:22 -0800 Organization: None to speak of Lines: 99 Message-ID: References: <87shnab3c5.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: mx02.eternal-september.org; posting-host="13068d66eab4ac340fa1365bf7a469c0"; logging-data="30722"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19i4h24Sv+u/133GXTAqCji" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:cL8qFI0CA9chDYIQkgeFJ8HFdOE= sha1:U613aNODFpTz7z37uiVuJB2UROI= Xref: csiph.com comp.lang.c:104224 Ben Bacarisse writes: > BartC writes: > >> On 19/02/2017 03:20, Keith Thompson wrote: >> >>> struct {int a, C[10];} S; >>> sizeof S.C >>> >>> is actually quite straightforward. `S.C` is an expression of >>> array type. Since that expression is the operand of `sizeof`, it >>> is not converted to a pointer expression. (`C` by itself is not an >>> expression at all.) >> >> Given: >> >> int A[10], B[10], C[10], D[10][6], x,i,j; >> >> aren't (A,B,C) and (x?B?C) and D[i] expressions of array type too? > > There is certainly some problem here although I'm not sure where the > problem lies. S.C is usually thought of an expression with array type > (as are B and C in the declaration above), but it can't be that simple > or (x?B:C) would be illegal because array types are not allowed in the > second and third operand positions of ?: No, there's not really a problem. Given the declarations above, S.C is an expression of array type. It may or may not decay to a pointer expression, depending on its context. In (x?B:C), B and C are array expressions, and they decay to pointer expressions (since the ?: operator is neither sizeof nor &). > Maybe when the standard talks about the type of an expression it > normally refers to the type after the array-to-pointer conversion -- a > conversion that sizeof suppresses. Yes. The fact that array-to-pointer decay is described using the word "converted" might be a bit confusing. In the expression (x?B:C), the subexpression B *is* an expression of pointer type. The "conversion" ("adjustment" might have been a better word) happens at compile time. > That would make (x?B:C) legal > because B and C are then really expressions with compatible pointer > types. But if that's the case then (x,C) is also an expression with > pointer type and I'd expect that conversion to a pointer would also be > suppressed by sizeof. (x,C) is invalid because x and C are of integer and pointer type, respectively. `(A,B)` is of pointer type; the array subexpressions are operands of the comma operator, so they decay. `sizeof (A,B)` is perfectly valid, and yields the size of an int* pointer. A and B are still not operands of sizeof; only the parenthesized expression `(A,B)` is, and it's already of pointer type. The sizeof operator doesn't "reach into" the expression `(A,B)`, apply itself to the subexpressions `A` and `B`, and inhibit their array-to-pointer conversions. > When I first started following this thread, I thought the issue might be > related to lvalues since nether (x,C) not (X?B:C) are lvalue > expressions. Interestingly, in C90, the array to pointer conversion is > specifically described as converting array lvalues so there is nothing > for sizeof to suppress in sizeof (x,C) and the conversion happens only > in contexts where (x,C) is evaluated. > > In C99 and C11 that sentence has been amended to remove the word lvalue > so it applies to all expressions with array type. It's certainly true > that the conversion happens for some other non-lvalue expressions with > (apparently) array types. For example, after > > struct S { char C[10]; } S; > struct S f(void) { return S; } > > the epression f().C converts to a pointer as expected and sizeof f().C > suppresses the conversion. (In C99 and C11 xxx.member is an lvalue if > xxx is one and function call expressions are not. In C90 it's unstated > if f() is an lvalue though it probably isn't. gcc and clang (correctly, > I think) refuse to convert f().C to a pointer in any context in C90 > mode. I believe that an array member of a function call of struct type is the *only* case where it's possible to have an array expression that's not an lvalue in C90. In C90, the array-to-pointer conversion rules implicitly assumed that the array expression refers to an array object (to whose initial element the resulting pointer points). To fix that oversight, C99 introduced objects of *temporary lifetime*, so now there's an object for the resulting pointer to point to. > Anyway, sadly I'm posting only to express some confusion rather than > explanation. I hope I've helped clear up some of it. -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"