“初始化器元素不是常量”错误在Linux GCC中没有任何原因,编译C [duplicate]

时间:2022-08-03 04:26:58

This question already has an answer here:

这个问题已经有了答案:

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

我把我的主要。c文件并通过gcc -std=c1x -c main编译。c在Mac OS X上运行良好,没有错误。然后我在LinuxMint和覆盆子圆周率上做同样的事情,在这两种情况下,它都给了我关于“初始化元素不是常量”的错误。

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上也不需要)?

1 个解决方案

#1


21  

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

C的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在被嵌入后不能被修改。

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

对纬度的引用不是一个常量表达式。编译器当然可以在编译时评估这样的引用,但是C标准并不要求它这样做。(常量和非常量表达式之间的界限必须在某处画出来,语言的作者选择了相对简单的区分,很少有特殊情况。)

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.

显然C语言是可以定义的所以纬度是一个常数表达式。它是在c++中,我主张C采用类似的规则。但是在当前的C规则下,它不是,这意味着您不能在静态对象的初始化器中使用纬度。

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(我理解的编译器是在MacOS下输入gcc时被调用的编译器)很可能是不合格的,因为它不能诊断这个错误。在我自己的Linux系统上,我发现当使用-std=c11 -pedantic调用时,gcc 4.7.2可以正确地诊断错误,但clang 3.4不能。

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

除了2011年ISO C标准第6.6段第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接受纬度作为一个常量表达式,因为它利用了这个权限——但是,我仍然期望从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:

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的声明。

#1


21  

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

C的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在被嵌入后不能被修改。

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

对纬度的引用不是一个常量表达式。编译器当然可以在编译时评估这样的引用,但是C标准并不要求它这样做。(常量和非常量表达式之间的界限必须在某处画出来,语言的作者选择了相对简单的区分,很少有特殊情况。)

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.

显然C语言是可以定义的所以纬度是一个常数表达式。它是在c++中,我主张C采用类似的规则。但是在当前的C规则下,它不是,这意味着您不能在静态对象的初始化器中使用纬度。

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(我理解的编译器是在MacOS下输入gcc时被调用的编译器)很可能是不合格的,因为它不能诊断这个错误。在我自己的Linux系统上,我发现当使用-std=c11 -pedantic调用时,gcc 4.7.2可以正确地诊断错误,但clang 3.4不能。

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

除了2011年ISO C标准第6.6段第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接受纬度作为一个常量表达式,因为它利用了这个权限——但是,我仍然期望从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:

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的声明。