5 views

Skip to first unread message

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.

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

Reply all

Reply to author

Forward

0 new messages

Search

Clear search

Close search

Google apps

Main menu