I've already calculated that the following are valid and should not error, as both just end up with the character literal 'A' being their control expression. The unspecified value of the char* pointing to the string literal is eliminated during evaluation, so the fact it is unknowable doesn't matter. ('A' is assumed not be to mapped to NUL.) [GCC 4.2.1 accepts the first, and inconsistently considers *"A" to be an invalid control expression.]
#if "A"[0] #else #error "A"[0] is false #endif
#if *"A" #else #error *"A"[0] is false #endif
C99 6.4.4.1 does not clearly state that an integer literal is an object, so this should be invalid as the requirements of the address- of operator & are imposed even though neither * nor & are evaluated.
#if *&0 #error *&0 is true #endif
C99 6.4.5p5 goes into some detail regarding the exact layout of a string literal, so it is clear that a string literal points to an object -- at conceptual translation phase 7, three conceptual stages after preprocessing (conceptual stage 4). Does an implementation have license to assume said layout during preprocessing? Alternately, is the following required to be invalid even though **&"A" must be accepted at compile-time? :
#if **&"A" #else #error **&"A" is false #endif
If an implementation has license to accept the above example, is there some way to infer that it is actually required to accept the above example?
String literals are not permitted in integer constant expressions, see C99 6.6:
6 An integer constant expression96) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.
96) An integer constant expression is used to specify the size of a bit-field member of a structure, the value of an enumeration constant, the size of an array, or the value of a case constant. Further constraints that apply to the integer constant expressions used in conditional-inclusion preprocessing directives are discussed in 6.10.1.
-- "The lusers I know are so clueless, that if they were dipped in clue musk and dropped in the middle of pack of horny clues, on clue prom night during clue happy hour, they still couldn't get a clue." --Michael Girdwood, in the monastery
zaimoni@zaimoni.com writes: > I've already calculated that the following are valid and should not > error, as both just end up with the character literal 'A' being their > control expression. The unspecified value of the char* pointing to > the string literal is eliminated during evaluation, so the fact it is > unknowable doesn't matter. ('A' is assumed not be to mapped to NUL.)
'A' cannot be equal to 0 (NUL) in a conforming implementation.
> [GCC 4.2.1 accepts the first, and inconsistently considers *"A" to be > an invalid control expression.]
Both of these are constraint violations, requiring diagnostics.
C99 6.10.1p1:
The expression that controls conditional inclusion shall be an integer constant expression except that [...]
This is a constraint, so violating it requires a diagnostic.
C99 6.6p6 defines "integer constant expression"; it may not contain a string literal.
> C99 6.4.4.1 does not clearly state that an integer literal is an > object, so this should be invalid as the requirements of the address- > of operator & are imposed even though neither * nor & are evaluated.
> #if *&0 > #error *&0 is true > #endif
An integer constant is not an lvalue, so &0 is a constraint violation.
> C99 6.4.5p5 goes into some detail regarding the exact layout of a > string literal, so it is clear that a string literal points to an > object
No, a string literal does not point to an object. If it did, sizeof "hello" would yield sizeof(char*); instead, it yields 6, the size of the array object that corresponds to the string literal.
> -- at conceptual translation phase 7, three conceptual stages > after preprocessing (conceptual stage 4). Does an implementation have > license to assume said layout during preprocessing? Alternately, is > the following required to be invalid even though **&"A" must be > accepted at compile-time? :
> If an implementation has license to accept the above example, is there > some way to infer that it is actually required to accept the above > example?
As above, the example violates a constraint by attempting to use a string literal as part of an expression in a context that requires an integer constant expression. A conforming compiler must issue a diagnostic. Once it's done so, it may, but is not required to, continue to process the translation unit.
-- Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"
Keith Thompson <ks...@mib.org> writes: > zaimoni@zaimoni.com writes: >> #if "A"[0] >> #else >> #error "A"[0] is false >> #endif
> C99 6.10.1p1:
> The expression that controls conditional inclusion shall be an > integer constant expression except that [...]
> This is a constraint, so violating it requires a diagnostic.
Ordinarily I would agree, but C99 6.6p10 says, "An implementation may accept other forms of constant expressions." For me, at least, this muddies the water a bit. -- char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[] ={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6} ,*p =b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+ 2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
Ben Pfaff <b...@cs.stanford.edu> writes: > Keith Thompson <ks...@mib.org> writes: >> zaimoni@zaimoni.com writes: >>> #if "A"[0] >>> #else >>> #error "A"[0] is false >>> #endif
>> C99 6.10.1p1:
>> The expression that controls conditional inclusion shall be an >> integer constant expression except that [...]
>> This is a constraint, so violating it requires a diagnostic.
> Ordinarily I would agree, but C99 6.6p10 says, "An implementation > may accept other forms of constant expressions." For me, at > least, this muddies the water a bit.
Good point.
Hmm. Would additional forms of constant expressions be considered an "extension", and thus have to be documented?
In any case, it's certainly non-portable.
-- Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"
On Nov 5, 3:13 pm, Keith Thompson <ks...@mib.org> wrote:
> zaimoni@zaimoni.com writes: > > I've already calculated that the following are valid and should not > > error, as both just end up with the character literal 'A' being their > > control expression. The unspecified value of the char* pointing to > > the string literal is eliminated during evaluation, so the fact it is > > unknowable doesn't matter. ....
> > [GCC 4.2.1 accepts the first, and inconsistently considers *"A" to be > > an invalid control expression.]
> gcc 3.4.4 and 4.2.4 reject all of your examples.
> Both of these are constraint violations, requiring diagnostics.
> C99 6.10.1p1:
> The expression that controls conditional inclusion shall be an > integer constant expression except that [...]
> This is a constraint, so violating it requires a diagnostic.
> C99 6.6p6 defines "integer constant expression"; it may not contain a > string literal.
I have some test cases to move out of the C99 conformance suite elsewhere, then. (Looking elsewhere in-thread: "default" rather than "default.nonconforming" should be the correct subdirectory, thanks to C99 6.6p10.)
> > C99 6.4.5p5 goes into some detail regarding the exact layout of a > > string literal, so it is clear that a string literal points to an > > object
> No, a string literal does not point to an object. If it did, > sizeof "hello" > would yield sizeof(char*); instead, it yields 6, the size of the array > object that corresponds to the string literal.
Ok. (Not sure how that slipped through, as I've been exploiting that compile-time strlen sleight-of-hand fairly intensively for this.)