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.)