C语言要求静态对象的初始化器是一个常量表达式。(因为静态对象的初始化发生在main
开始之前,所以没有地方可以发生任何运行时的评估)。
C项的const
关键词并不意味着 "不变",尽管这两个词显然是相关的。A恒定表达是指可以,而且在某些情况下必须,在编译时进行评估的。const
表示只读。例如,在块的范围内(在一个函数定义内),这个。
const int r = rand();
是完全合法的。显然,初始化器不能在编译时被评估;const
只是意味着r
在被初始化后不能被修改。
When you write:
const unsigned long long LATITUDE = (long) 3600000;
a reference to LATITUDE
is not a 恒定表达. 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-恒定表达s had to be drawn somewhere, and the authors of the language chose to make the distinction relatively simple, with few special cases.)
现在,C语言当然是真的could have been defined so that LATITUDE
is a 恒定表达. 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.
这也意味着clang
(据我所知,在MacOS下输入gcc
时调用的编译器)很可能不符合要求,因为它不能诊断出这个错误。在我自己的Linux系统上,我发现,当用-std=c11 -pedantic
调用时,gcc 4.7.2正确地诊断了这个错误,但clang 3.4却没有。
Except 也许本条款来自2011年ISO C标准的第6.6节第10段(1990年和1999年的标准中也有此内容)。
An implementation may accept other forms of 恒定表达s.
It's conceivable that clang accepts LATITUDE
as a 恒定表达 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.
更新 : 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;
在clang 3.0中使用选项-std=c99 -pedantic
,我得到了。
c.c:7:14: warning: expression is not integer constant expression (but is allowed as an extension) [-pedantic]
case LATITUDE:
^~~~~~~~
1 warning generated.
在clang 3.4中,警告是。
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 恒定表达; the bug is that it doesn't warn about the declaration of MAX_COORDINATES_NUMBER
.
ANOTHER 更新 :
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);
前两个声明中的(long)
的转换是没有用的。常量3600000
和1810000
(可能)属于int
类型。你把它们转换为long
,然后用这个结果来初始化一个unsigned long long
类型的对象。只需去掉转换 -- 或者,如果你想更明确一些,添加一个ULL
的后缀,使常数成为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 恒定表达. 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 恒定表达, you can make it a macro as well:
#define LATITUDE 3600000ULL