I encountered a confusing case when I was doing semantic analysis for my compiler course.
#include <stdio.h>
int a = "abcd"[2];
int main()
{
char b = "abcd"[2];
printf("%d\n%c\n", a, b);
return 0;
}
GCC says "error: initializer element is not constant" for variable "a".
Why?
It's not inside a function, which means it has to be an initializer - which is assigned only when the item is declared - which means it must be a constant value at compile time, which malloc cannot be.
Moreover, in C language, the term "constant" refers to literal constants (like 1 , 'a' , 0xFF and so on), enum members, and results of such operators as sizeof . Const-qualified objects (of any type) are not constants in C language terminology.
Constant initialization is performed after zero initialization of the static and thread-local objects and before all other initialization. Only the following variables are constant initialized: 1) Static or thread-local references, if it is bound to static lvalue, to a temporary, or to a function.
The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.
The C language requires initializers for global variables to be constant expressions. The motivation behind this is for the compiler to be able to compute the expression at compile time and write the computed value into the generated object file.
The C standard provides specific rules for what is a constant expression:
- An integer constant expression117) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants,
sizeof
expressions whose results are integer constants,_Alignof
expressions, 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 thesizeof
or_Alignof
operator .- More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:
- an arithmetic constant expression,
- a null pointer constant,
- an address constant, or
- an address constant for a complete object type plus or minus an integer constant expression.
As you can see non of the cases include an array access expression or a pointer dereference. So "abcd"[2]
does not qualify as a constant expression per the standard.
Now the standard also says:
- An implementation may accept other forms of constant expressions.
So it would not violate the standard to allow "abcd"[1]
as a constant expression, but it's also not guaranteed to be allowed.
So it's up to you whether or not to allow it in your compiler. It will be standard compliant either way (though allowing it is more work as you need another case in your isConstantExpression
check and you need to actually be able to evaluate the expression at compile time, so I'd go with disallowing it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With