To clarify existing practice, several varieties of constant expression have been identified:
The expression following #if
(§3.8.1)
must expand to integer constants,
character constants,
the special operator defined
,
and operators with no side effects.
No environmental inquiries can be made,
since all arithmetic is done as translate-time
(signed or unsigned) long integers,
and casts are disallowed.
The restriction to translate-time arithmetic frees an
implementation from having to perform execution-environment
arithmetic in the host environment. It does not preclude
an implementation from doing so --- the implementation may
simply define ``translate-time arithmetic'' to be that of the
target.
Unsigned arithmetic is performed in these expressions
(according to the default widening rules)
when unsigned operands are involved;
this rule allows for unsurprising arithmetic involving very large
constants (i.e, those whose type is unsigned long
)
since they cannot be represented as long
or constants explicitly marked as unsigned.
Character constants, when evaluated
in #if
expressions, may be interpreted in the source character
set, the execution character set, or some other implementation-defined
character set.
This latitude reflects the diversity of existing practice,
especially in cross-compilers.
An integral constant expression
must involve only numbers knowable at translate time,
and operators with no side effects.
Casts and the sizeof
operator may be used to interrogate the execution environment.
Static initializers include integral constant expressions, along with floating constants and simple addressing expressions. An implementation must accept arbitrary expressions involving floating and integral numbers and side-effect-free operators in arithmetic initializers, but it is at liberty to turn such initializers into executable code which is invoked prior to program startup (see §2.1.2.2); this scheme might impose some requirements on linkers or runtime library code in some implementations.
The translation environment must not produce a less accurate value for a floating-point initializer than the execution environment, but it is at liberty to do better. Thus a static initializer may well be slightly different than the same expression computed at execution time. However, while implementations are certainly permitted to produce exactly the same result in translation and execution environments, requiring this was deemed to be an intolerable burden on many cross-compilers.
#if
expressions to determine properties of
the execution environment may now get different answers.