ISO: WG21/N0493
ANSI: 94-0106
Authors: John Max Skaller
Date: May 1994
Reply to: maxtal@suphys.physics.su.oz.au
"CONSTANT EXPRESSIONS"
----------------------
Minor editorial corrections to definition of constant expressions.
Problem 1: Initialiser Visibility
---------------------------------
The description of constant expressions in the Working
Paper is incorrect. The WP states:
"A constant-expression can involve only literals, enumerators,
const values of integral types initialised with constant expressions
and sizeof expressions."
Consider:
// file 1
extern const int a;
char x[a];
// file 2
extern const int a = 42;
Under the current rules, there is no error here: a is a const
integral type initialised by a constant expression.
We doubt any compiler could compile this code correctly.
A similar but less striking example is:
extern const int a;
char x[a];
const int a = 42;
Its clear the intent is that the initialiser must be visible
at the point of use -- this mechanism is designed to replace
use of #define.
On examining the ISO C Standard, we find that
"A constant expression .. can be used in any place that a constant
can be"
it is quite plain that for a variable to be used as a constant
expression, the initialiser must be visible.
Unfortunately, that is not enough specification. Consider:
extern const int a;
const int b = a;
const int a = 42;
char x[b];
Here, the initialisers for both a and b are visible and the value 42
of both can be computed at compile time recursively or by back patching.
Should we require this?
Our answer is no. Whether a variable may be used as a constant
expression or not, and its value if it is, should be determinable
when the initialiser is seen and not silently adjusted by
subsequent definitions. Thus, 'b' above is not a constant expression,
so the fragment is ill formed.
Editorial Action: Reword the section on constant
expressions so it is as plain as day that a variable may be used
as a constant expression only if its definition
is visible and its initialiser is a constant expression.
(This is a necessary but not sufficient condition)
-----------------------------------------------------------------------
Problem 2: C allows non-intergral constant expressions
------------------------------------------------------
The description of constant expressions in the Working
Paper applies only to const integral types.
(Actually, it is misworded, claiming a requirement
for a "constant value" which is absurd.)
But the ISO C Standard permits floating constant expressions,
null pointer constant, address constants and
an address plus or minus an arithmetic constant
expression. In addition the implementation may accept other
forms of constant expression.
The definition of constant expression and the forms allowed is
crucial in C++ because it affects the order of initialisation.
C requires initialisers to be constant expressions. C++ permits
dyanamic initialisation. Conceptually, all the "C" initialisations
are done first, together with 0 initialisation if no initialiser
is given, then the dynamic initialisations are performed.
I propose both floating and pointer constants be permitted
as per ISO C. I propose all non-volatile const arithmetic and pointer
variables are constant expressions, not just combinations of
literals and const integral variables.
Editorial Action: Incorporate the bulk of the description
in the ISO C Standard 6.4. Omit "An implementation may accept
other forms of constant expressions".
-----------------------------------------------------------------------
Problem 3. Preprocessor constant expressions
---------------------------------------------
The ARM and WP incorrectly use the same term "constant expression"
in the description of preprocessor expressions.
Because of the phases of translation, preprocessor
constant expressions cannot depend on const integral
variables initialised by constant expressions:
const int n = 1;
#if n == 1
//??
Editorial Action: Use the term "preprocessor constant expression"
to distinguish them from C++ language (integral) constant
expressions.