Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operators indirectly forbidden (or not?) in defining integer constant expressions (in C)

In standard C (C99/C11) we have the so-called integer constant expressions, which are constant expressions whose operands are all constant integers.

The following definition applies:

Standard C99, Section 6.6(par.6):

An integer constant expression) shall have integer type and shall only have operands that are integer costants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts.

Standard C99

This appears after the definition of the more general constant expression.
(Since integer constant expression are defined after constant expression, I assume that the former is a particular case of the last.)

On the other hand, conditional expressions are considered constant expressions, constrained by the following rule:

Standard C99, Section 6.6:

Constant expressions shall not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is not evaluated.

By unrolling the meaning of conditional expression we can fall down to postfix expressions and/or unary expressions.

Now, if we apply these constraints to integer constant expressions, we roughly obtain that they consist of conditional expressions restricted in such a way that every operand is integer/enumeration/character constants (or floating constant immediately preceded by a cast), and such that there are no assignment, increment, decrement, function-call or comma operators.

  • By simplicity, let us suppose that E is a such expression, without any sizeof operator and without non-evaluated operands.

MY QUESTION IS:
Are the following operators indirectly forbidden in E:

  • & (address),
  • * (indirection),
  • [] (array-subscript),
  • . (struct member),
  • -> (pointer to struct members).

In addition, are compound literals also forbidden?

Aditional note: I am interested in answering this question for strict conforming programs (C99/C11).

I think that they cannot be in any subexpression of E, but I am not sure if this is completely true. My quick reasoning is as follows:

  • If F is an integer constant subexpression of E, then F has, by definition, an integer type T.
  • If the unary operator & appears before F in E, then &F ins an operand having type "pointer to T", which is not allowed in E (in despite of that F is not an object, but only an integer value, so & cannot be applied). Thus & cannot appear in any E.
  • Since F has not any pointer type, it has no sense the expression *F.
  • A subscript operator [] is used to indicate an element inside an array. This means that we would have in E something like A[N]. Here, N must be an integer constant expression. However we note that A is also an operand, but it is an object of type array, which is not allowed in E. This implies that the array-subscript operator cannot appear in E.
  • If we have in E the operators . and ->, it implies they are used inside E as follows: S.memb pS->memb. Thus, we have the operand S whose type is struct or union and pS which is a pointer to struct or pointer to union. But these kind of "operands" are not allowed in E.
  • Compound literals are not allowed in E, because they are lvalues, which implies they will have an address when the program runs. Since such an address cannot be known by the compiler, the expression involving a compound literal is not considered a constant.

Do you think that my reasonings are right?
Do you know exceptional cases in that some of these operators or expressions can be [part of] an integer constant expression (as in the restricted case that I denoted E).

like image 469
pablo1977 Avatar asked Feb 24 '14 18:02

pablo1977


1 Answers

An ICE only has to have values (rvalues in the jargon) as primary expressions that constitute it, and no objects (lvalues).

If you build up from there to exclude operators you see that

  • none of the operators that need an lvalue as operand can be used (assignment, increment, decrement, unary &)

  • none of the operators that produce an lvalue can be used either (unary *, array member [], member ->)

  • the . operators that needs a struct as argument, since

    • there are no literals for struct

    • Compound literals are a misnomer, they are objects.

    • Function calls are not allowed either.

Some of these operators can appear in places when they are not evaluated (or not supposed not to be), in particular _Alignof, the macro offsetof and some appearances of sizeof.

like image 72
Jens Gustedt Avatar answered Oct 26 '22 10:10

Jens Gustedt