The C language requires the initializer for a static object to be a constant expression. (Since initialization of static objects occurs before main
begins, there's no place for any run-time evaluation to happen.)
C's const
keyword does not mean "constant", though the words are obviously related. A constant expression is one that can be, and in some cases must be, evaluated at compile time. const
means read-only. For example, at block scope (inside a function definition), this:
const int r = rand();
is perfectly legal. Obviously the initializer can't be evaluated at compile time; the const
merely means that r
may not be modified after it's been initalized.
When you write:
const unsigned long long LATITUDE = (long) 3600000;
a reference to LATITUDE
is not a constant expression. A compiler certainly could evaluate such a reference at compile time, but the C standard doesn't require it to. (The line between constant and non-constant expressions had to be drawn somewhere, and the authors of the language chose to make the distinction relatively simple, with few special cases.)
Now it's certainly true that the C language could have been defined so that LATITUDE
is a constant expression. It is in C++, and I've argued for C to adopt a similar rule. But under current C rules, it's not, which means that you can't use LATITUDE
in the initializer for a static object.
This also means that clang
(the compiler that, as I understand it, is the one invoked when you type gcc
under MacOS) is very likely non-conforming, because it fails to diagnose this error. On my own Linux system, I find that, when invoked with -std=c11 -pedantic
, gcc 4.7.2 correctly diagnoses the error, but clang 3.4 does not.
Except perhaps for this clause from section 6.6 paragraph 10 of the 2011 ISO C standard (which also exists in the 1990 and 1999 standards):
An implementation may accept other forms of constant expressions.
It's conceivable that clang accepts LATITUDE
as a constant expression because it takes advantage of this permission -- but then I'd still expect at least a warning from clang -std=c11 -pedantic -Wall -Wextra
, and there is none.
UPDATE : When I compile the following:
#include <stdio.h>
const unsigned long long LATITUDE = (long) 3600000;
int main(void) {
switch (0) {
case LATITUDE:
puts("wrong");
break;
default:
puts("ok(?)");
break;
}
}
with clang 3.0 with options -std=c99 -pedantic
, I get:
c.c:7:14: warning: expression is not integer constant expression (but is allowed as an extension) [-pedantic]
case LATITUDE:
^~~~~~~~
1 warning generated.
With clang 3.4, the warning is:
c.c:7:14: warning: expression is not an integer constant expression; folding it to a constant is a GNU extension [-Wgnu-folding-constant]
case LATITUDE:
^~~~~~~~
1 warning generated.
So clang does recognize that it's not a constant expression; the bug is that it doesn't warn about the declaration of MAX_COORDINATES_NUMBER
.
ANOTHER UPDATE :
The code in the question is:
const unsigned long long LATITUDE = (long) 3600000;
const unsigned long long LONGITUDE = (long) 1810000;
const unsigned long long MAX_COORDINATES_NUMBER = (LATITUDE-1) + LATITUDE*(LONGITUDE-1);
The (long)
casts in the first two declarations are not useful. The constants 3600000
and 1810000
are (probably) of type int
. You convert them to long
and then use the result to initialize an object of type unsigned long long
. Just drop the cast -- or, if you want to be more explicit, add a ULL
suffix to make the constants unsigned long long
:
const unsigned long long LATITUDE = 3600000ULL;
const unsigned long long LONGITUDE = 1810000ULL;
The problem is on the third declaration, which refers to LATITUDE
and LONGITUDE
, neither of which is a constant expression. Unfortunately C doesn't provide a good way to define named constants of integer types other than int
(you can (ab)use the enum
feature for int
constants). The alternative is to use macros. This works:
#define LATITUDE 3600000ULL
#define LONGITUDE 1810000ULL
const unsigned long long MAX_COORDINATES_NUMBER = (LATITUDE-1) + LATITUDE*(LONGITUDE-1);
And if you need MAX_COORDINATES_NUMBER
to be a constant expression, you can make it a macro as well:
#define LATITUDE 3600000ULL
#define LONGITUDE 1810000ULL
#define MAX_COORDINATES_NUMBER ((LATITUDE-1) + LATITUDE*(LONGITUDE-1))
(The extra parentheses are needed to avoid operator precedence problems when you use MAX_COORDINATES_NUMBER
in a larger expression.)
sizeof
and_Alignof
expressions, and your first two variables here are not constants. I'm not sure why clang allows this, although 6.6.10 does say an implementation is allowed to accept other forms of constant expressions. The arithmetic is fine - if you replace those first two statements with#define
s, orenum
s, it'll work as you'd expect. – VasyutaULL
at the end of your numbers. – VasyutaLATITUDE
andLONGITUDE
aslong long
, but initialize them with casts tolong
. If you drop the cast, an integer constant like3600000
is of some time in which its value can be represented (unless it exceedsLLONG_MAX
). Or you can write3600000LL
if you want to be more explicit. – Kaetelong long
values, and I didn't want to make the program have to convert them every time. – Exorcistconst unsigned long long LATITUDE = (long) 3600000;
– Kaete