Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Constant expressions

5 views
Skip to first unread message

Joseph Samuel Myers

unread,
Jan 19, 2004, 12:20:16 PM1/19/04
to
A version of the following analysis of the problems with constant
expressions was previously sent to the UK C Panel. Perhaps a wider
audience would be worthwhile.

Problems with constant expressions in C99
=========================================

(1) There are the problems in DR#261 the UK C Panel submitted a couple
of years ago. This is where the Oxford minutes say "DR 261. Clive
had potential sticking points and will converse with interested
parties." and "ACTION: CF to draft words describing the four uses of
the term constant to be considered in the response to DR 261. DONE
merged in here or a separate document? I don't have them.".

The actual wording proposed in that DR about "translation-time values"
is problematic because expressions with translation-time values don't
seem to be restricted to those that would be *integer* constant
expressions. Null pointer constants require *integer* constant
expressions. Arrays require *integer* constant expressions not to be
VLAs, but *any* type of constant expression suffices to require the
constraint on the size being > 0 to be checked (this is probably a
defect, but should be separately noted if being fixed in the course of
fixing another defect).

int x[(int)(double)1.0];

is a VLA while

int x[(int)(double)0.0];
int y[(int)-1.0];

are both constraint violations, although the expressions are only
arithmetic constant expressions.

(2) The UK C Panel couldn't agree when we discussed the issue about
whether the changes in C99 (where comma expressions may appear in an
unevaluated subexpression of a constant expression outside sizeof -
including possibly in the preprocessor) were intended or not (so that
draft DR didn't get submitted). This may not be a defect, but the
effect is that there are in effect several flags on subexpressions
(and on types appearing within expressions) that must maintained by an
implementation in order to determine whether an expression is a
constant expression and, if so, what sort of constant expression it
is; some non-constant subexpressions are OK in integer constant
expressions if they are within an unevaluated subexpression, while
some are only OK within sizeof. Furthermore, a sizeof expression
whose result is not an integer constant may be OK within an
unevaluated part of an arithmetic constant expression - as long as it
does not contain a cast of prohibited form - but not within an
unevaluated part of an integer constant expression. It isn't even
immediately obvious from the definitions that all integer constant
expressions are also arithmetic constant expressions (although I
believe this to be so).

(3) Address constants can contain casts to variably modified types, which
might be a defect <http://groups.google.com/groups?th=35e7db17bfb8414f>.
If you cast to such a type (while keeping the expression in fact a
constant), any nonconstants directly in the sequence of tokens for the
type (as opposed to in a typedef) are also subject to the constraints
on what may only appear in unevaluated subexpressions, and probably to
those on permitted operands (see also item 5 below).

(4) When exactly can "other forms" of constant expressions (6.6
paragraph 10) be accepted? A common but not universal view on
comp.std.c, e.g.
<http://groups.google.com/groups?selm=3990A4BA...@wizard.net>),
is that they can't be accepted as integer constant expressions (or one
of the other types enumerated), only as some type in addition to
those, that can be accepted in initializers (or, I suppose, allowed in
constraint checking for VLAs having positive size), and that any such
forms must follow the Syntax, Description and Constraints sections of
6.6, but this could be made much clearer.

(5) What are the "operands" (6.6 paragraphs 6 and 8) of a constant
expression? Presumably it means the "ultimate" operands in some
sense, recursing down various operators to their operands, but this
isn't specififed. Presumably compound literals such as (const int){0}
are not meant to be constant expressions (being references to
anonymous variables), but it is hardly clear from the text that 0
isn't the operand here. Also, one would expect that parentheses are
meant to be purely syntactic rather than having "operands", so that
(int)(0.0) is an integer constant expression just as (int)0.0 is, and
((void *)0) is a null pointer constant, but this is nowhere stated.

(6) We know from 6.5.3.4 paragraph 2 that sizeof of a non-VLA is an
integer constant. Is it also the case that sizeof of a VLA is *never* an
integer constant, or indeed never counts as a constant? Can it be shown
from the standard that sizeof(int [(int)(double)1.0]) isn't an arithmetic
constant expression - or is it?

(7) May address constants use array indices that are arithmetic
constant expressions but not integer constant expressions?

(8) 6.6 paragraph 7 says that a constant expression in an initializer
"shall be, or evaluate to" one of four possibilities. When does "be"
apply, and when does "evaluate to" apply? (Expressions *are* expressions
(pieces of source code), but *evaluate to* values (something more
abstract, but with no intersection with pieces of source code), so only
one can apply in each case.)

* an arithmetic constant expression - this is a type of expression, so
"be" applies.

* a null pointer constant - a type of expression, so "be" applies.

* an address constant - a type of value (with some associated restrictions
on the expression behind the value), so "evaluate to" applied.

* an address constant for an object type plus or minus an integer constant
expression - some sort of hybrid to which neither applies.

What of

static int x[10];
static int *p = 1 + x + 9 - 0 + 0;

? Is this valid? Pointing one past the end of an array, it clearly falls
outside the definition of "address constant". But the syntax doesn't make
it clearly syntactically of the form (address constant) +/- (integer
constant expression). What about the null pointer (void *)(void *)(int)0?
That's created by casting an integer constant expression to pointer type -
but the rules for address constants refer to "an integer *constant* cast
to pointer type".

I think a proper fix for this last issue is to specify all standard types
of constant expression syntactically, with a more precise (unified?)
definition of the last two.

--
Joseph S. Myers
js...@cam.ac.uk

0 new messages