Vaporware C99 preprocessor: string literal corner cases

Z

zaimoni

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?
 
B

Ben Pfaff

#if "A"[0]
#else
#error "A"[0] is false
#endif

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.
 
K

Keith Thompson

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.
 
B

Ben Pfaff

Keith Thompson said:
#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.
 
K

Keith Thompson

Ben Pfaff said:
Keith Thompson said:
#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.
 
Z

zaimoni

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.)
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.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Type of a string literal 13
preprocessor 2
Preprocessor 0
string literal initializer 15
preprocessor trick 4
preprocessor bug? 2
string literal declaration 6
Preprocessor integer arithmetic 3

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,744
Latest member
CortneyMcK

Latest Threads

Top