Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC doesn't support simple integer constant expression?

Tags:

c

gcc

c99

GCC 4.9 and 5.1 reject this simple C99 declaration at global scope. Clang accepts it.

const int a = 1, b = a; // error: initializer element is not constant

How could such a basic feature be missing? It seems very straightforward.

like image 336
Potatoswatter Avatar asked May 11 '15 01:05

Potatoswatter


2 Answers

C991 section 6.6 Constant expressions is the controlling section. It states in subsections 6 and 7:

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

Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.

The definition of integer and floating point constants is specified in 6.4.4 of the standard, and it's restricted to actual values (literals) rather than variables.

7/ More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following (a) an arithmetic constant expression, (b) a null pointer constant, (c) an address constant, or (d) an address constant for an object type plus or minus an integer constant expression.

Since a is none of those things in either subsection 6 or 7, it is not considered a constant expression as per the standard.

The real question, therefore, is not why gcc rejects it but why clang accepts it, and that appears to be buried in subsection 10 of that same section:

10/ An implementation may accept other forms of constant expressions.

In other words, the standard states what an implementation must allow for constant expressions but doesn't limit implementations to allowing only that.


1 C11 is much the same other than minor things like allowing _Alignof as well as sizeof.

like image 65
paxdiablo Avatar answered Nov 19 '22 19:11

paxdiablo


This is just the rules of C. It has always been that way. At file scope, initializers must be constant expressions. The definition of a constant expression does not include variables declared with const qualifier.

The rationale behind requiring initializers computable at compile-time was so that the compiler could just put all of the initialized static data as a bloc in the executable file, and then at load time that bloc is loaded into memory as a whole and voila, the global variables all have their correct initial values without any code needing to be executed.

In fact if you could have executable code as initializer for global variables, it introduces quite a lot of complication regarding which order that code should be run in. (This is still a problem in modern C++).

In K&R C, there was no const. They could have had a rule that if a global variable is initialized by a constant expression, then that variable also counts as a constant expression. And when const was added in C89, they could have also added a rule that const int a = 5; leads to a constant expression.

However they didn't. I don't know why sure, but it seems likely that it has to do with keeping the language simple. Consider this:

extern const int a, b = a;

with const int a = 5; being in another unit. Whether or not you want to allow this, it is considerably more complication for the compiler, and some more arbitrary decisions.

If you look at the current C++ rules for constant expressions (which still are not settled to everyone's satisfaction!) you'll see that each time you add support for one more "obvious" thing then there are two other "obvious" things that are next in line and it is never-ending.

In the early days of C, in the 1970s, keeping the compiler simple was important so it may have been that making the compiler support this meant the compiler used too many system resources, or something. (Hopefully a coder from that era can step in and comment more on this!)

Finally, the C89 standardization was quite a contentious process since there were so many different C compilers that had each gone their own way with language evolution. Demanding that a compiler vendor who doesn't support this, change their compiler to support it might be met with opposition, lowering the uptake of the standard.

like image 23
M.M Avatar answered Nov 19 '22 20:11

M.M