Linux GCC中无缘无故的“初始化器元素不是常量”错误,编译C
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21592494/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Initializer element is not constant" error for no reason in Linux GCC, compiling C
提问by sudo
I take my main.c file and compile it with gcc -std=c1x -c main.c in Mac OS X, and it works fine with no errors. Then I do the exact same thing in LinuxMint and on a Raspberry Pi, and in both cases, it gives me errors about "initializer element is not constant".
我使用我的 main.c 文件并在 Mac OS X 中使用 gcc -std=c1x -c main.c 编译它,它运行良好,没有错误。然后我在 LinuxMint 和 Raspberry Pi 上做完全相同的事情,在这两种情况下,它都会给我关于“初始化元素不是常量”的错误。
One example of a problematic line with relevant code:
带有相关代码的问题行的一个示例:
//STATIC GLOBAL CONSTANTS
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); //compiler error: initializer element is not constant
It's supposed to let me do arithmetic, right? I could just replace that with the actual numbers, and it would work, but then it would become messy. And it works fine on my Mac anyway. Is there some option in GCC I have to specify on Linux (besides -std=c1x, which you also don't need on Mac)?
它应该让我做算术,对吧?我可以用实际数字替换它,它会起作用,但它会变得混乱。无论如何,它在我的 Mac 上运行良好。我必须在 Linux 上指定 GCC 中的某些选项(除了 -std=c1x,您在 Mac 上也不需要)?
采纳答案by Keith Thompson
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 语言要求静态对象的初始值设定项是常量表达式。(因为静态对象的初始化发生在main
开始之前,所以没有任何运行时评估发生的地方。)
C's const
keyword does not mean "constant", though the words are obviously related. A constant expressionis 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:
C 的const
关键字并不意味着“常量”,尽管这些词显然是相关的。甲常量表达式是一个,可以是,在某些情况下,必须在编译时,评价。const
表示只读。例如,在块作用域(在函数定义内),这个:
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.
是完全合法的。显然不能在编译时评估初始化器;在const
那只是意味着r
可能没有后进行修改一直initalized。
When you write:
当你写:
const unsigned long long LATITUDE = (long) 3600000;
a reference to LATITUDE
is not a constant expression. A compiler certainly couldevaluate 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.)
对的引用LATITUDE
不是常量表达式。编译器当然可以在编译时评估这样的引用,但 C 标准不要求这样做。(常量和非常量表达式之间的界限必须在某处画出来,语言的作者选择使区别相对简单,很少有特殊情况。)
Now it's certainly true that the C language couldhave 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.
现在是千真万确的C语言可以被定义,以便LATITUDE
为常量表达式。它是在 C++ 中,我一直主张 C 采用类似的规则。但是根据当前的 C 规则,它不是,这意味着您不能LATITUDE
在静态对象的初始化程序中使用。
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.
这也意味着clang
(根据我的理解,编译器是您gcc
在 MacOS 下键入时调用的编译器)很可能不符合标准,因为它无法诊断此错误。在我自己的 Linux 系统上,我发现当用 调用时-std=c11 -pedantic
,gcc 4.7.2 可以正确诊断错误,但 clang 3.4 没有。
Except perhapsfor this clause from section 6.6 paragraph 10 of the 2011 ISO C standard (which also exists in the 1990 and 1999 standards):
除了也许从第6.6节,2011年ISO C标准的第10段(其也存在于1990和1999的标准)这个子句:
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.
可以想象, clang 接受LATITUDE
作为一个常量表达式,因为它利用了这个权限——但是我仍然希望至少有一个来自 的警告clang -std=c11 -pedantic -Wall -Wextra
,并且没有。
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:
使用带有 options 的 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.
With clang 3.4, the warning is:
使用 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 constant expression; the bug is that it doesn't warn about the declaration of MAX_COORDINATES_NUMBER
.
所以 clang 确实认识到它不是一个常量表达式;错误在于它没有警告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
:
(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 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:
问题出在第三个声明上,它引用了LATITUDE
and LONGITUDE
,这两个声明都不是常量表达式。不幸的是,C 没有提供定义整数类型命名常量的好方法,除了int
(您可以(ab)使用常量的enum
功能int
)。另一种方法是使用宏。这有效:
#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:
如果你需要MAX_COORDINATES_NUMBER
成为一个常量表达式,你也可以把它变成一个宏:
#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.)
(MAX_COORDINATES_NUMBER
在更大的表达式中使用时,需要额外的括号以避免运算符优先级问题。)