By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
455,431 Members | 1,736 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 455,431 IT Pros & Developers. It's quick & easy.

Vaporware C99 preprocessor: string literal corner cases

P: n/a
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?
Nov 5 '08 #1
Share this Question
Share on Google+
4 Replies


P: n/a
za*****@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.]
gcc 3.4.4 and 4.2.4 reject all of your examples.
#if "A"[0]
#else
#error "A"[0] is false
#endif

#if *"A"
#else
#error *"A"[0] is false
#endif
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 **&"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?
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"
Nov 5 '08 #2

P: n/a
Keith Thompson <ks***@mib.orgwrites:
za*****@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,0xa6 7f6aaa,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;}}}
Nov 5 '08 #3

P: n/a
Ben Pfaff <bl*@cs.stanford.eduwrites:
Keith Thompson <ks***@mib.orgwrites:
>za*****@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"
Nov 5 '08 #4

P: n/a
On Nov 5, 3:13*pm, Keith Thompson <ks...@mib.orgwrote:
zaim...@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.
Rechecked...yes for 4.2.1.
#if "A"[0]
#else
#error "A"[0] is false
#endif
#if *"A"
#else
#error *"A"[0] is false
#endif

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.)
Nov 5 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.