Error "initializer element is not constant" when trying to initialize variable with const (7个答案)
Closed 7年前 .

我拿着我的main.c文件,在Mac OS X中用gcc -std=c1x -c main.c进行编译,它工作正常,没有错误。然后我在LinuxMint和Raspberry Pi上做了完全相同的事情,在这两种情况下,它都给出了关于 "初始化元素不是常量 "的错误。

有问题的一行的一个例子,有相关的代码。

//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

它应该让我做算术,对吗?我可以用实际的数字来代替它,这样就可以了,但这样就会变得很混乱。而且它在我的Mac上也能正常工作。GCC中是否有一些选项我必须在Linux上指定(除了-std=c1x,你在Mac上也不需要)?

5 个评论
这只是一个C语言的问题。根据 C11 6.6.6,整数常量表达式的操作数必须是常量,或者是sizeof_Alignof表达式,而你这里的前两个变量不是常量。我不知道为什么clang允许这样做,尽管6.6.10确实说过一个实现允许接受其他形式的常量表达式。算术很好--如果你用#defineenum替换前两个语句,就会像你所期望的那样工作。
sudo
@PaulGriffiths 这确实解决了问题,但在其他一些情况下,我需要长长的,而不是int。
sudo
@ruakh 在LinuxMint是4.8.1。当我在Mac上做的时候,它说是4.2.1,但后来苹果LLVM 5.0,所以我猜它不是真正的同一个GCC。
@9000:在你的数字后面加上ULL即可。
"无缘无故" -- 请避免提出这种说法;有一个相当合理的理由。
c
linux
macos
gcc
sudo
sudo
发布于 2014-02-06
1 个回答
Keith Thompson
Keith Thompson
发布于 2014-02-06
已采纳
0 人赞同

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)的转换是没有用的。常量36000001810000(可能)属于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