C语言 尝试使用 const 初始化变量时出现错误“初始化元素不是常量”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3025050/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:39:00  来源:igfitidea点击:

Error "initializer element is not constant" when trying to initialize variable with const

cinitialization

提问by tomlogic

I get an error on line 6 (initialize my_foo to foo_init) of the following program and I'm not sure I understand why.

我在以下程序的第 6 行(将 my_foo 初始化为 foo_init)出现错误,我不确定我明白为什么。

typedef struct foo_t {
    int a, b, c;
} foo_t;

const foo_t foo_init = { 1, 2, 3 };
foo_t my_foo = foo_init;

int main()
{
    return 0;
}

Keep in mind this is a simplified version of a larger, multi-file project I'm working on. The goal was to have a single constant in the object file, that multiple files could use to initialize a state structure. Since it's an embedded target with limited resources and the struct isn't that small, I don't want multiple copies of the source. I'd prefer not to use:

请记住,这是我正在处理的一个更大的多文件项目的简化版本。目标是在目标文件中有一个常量,多个文件可以使用它来初始化状态结构。由于它是一个资源有限的嵌入式目标并且结构不是那么小,我不想要源的多个副本。我不想使用:

#define foo_init { 1, 2, 3 }

I'm also trying to write portable code, so I need a solution that's valid C89 or C99.

我也在尝试编写可移植的代码,所以我需要一个有效的 C89 或 C99 的解决方案。

Does this have to do with the ORGs in an object file? That initialized variables go into one ORG and are initialized by copying the contents of a second ORG?

这与目标文件中的 ORG 有关系吗?初始化的变量进入一个 ORG 并通过复制第二个 ORG 的内容来初始化?

Maybe I'll just need to change my tactic, and have an initializing function do all of the copies at startup. Unless there are other ideas out there?

也许我只需要改变我的策略,并有一个初始化函数在启动时完成所有的副本。除非那里有其他想法?

回答by AnT

In C language, objects with static storage duration have to be initialized with constant expressions, or with aggregate initializers containing constant expressions.

在 C 语言中,具有静态存储期的对象必须使用常量表达式或包含常量表达式的聚合初始值设定项进行初始化。

A "large" object is never a constant expression in C, even if the object is declared as const.

“大”对象永远不是 C 中的常量表达式,即使该对象被声明为const.

Moreover, in C language, the term "constant" refers to literal constants(like 1, 'a', 0xFFand so on), enum members, and results of such operators as sizeof. Const-qualified objects (of any type) are not constantsin C language terminology. They cannot be used in initializers of objects with static storage duration, regardless of their type.

另外,在C语言中,术语“恒定”是指文字常数(如1'a'0xFF等等),枚举成员,并且这样的运营商的结果sizeof。Const 限定的对象(任何类型)不是C 语言术语中的常量。无论它们的类型如何,它们都不能用于具有静态存储持续时间的对象的初始值设定项。

For example, this is NOTa constant

例如,这不是一个常数

const int N = 5; /* `N` is not a constant in C */

The above Nwould be a constant in C++, but it is not a constant in C. So, if you try doing

以上N在 C++ 中是一个常量,但在 C 中它不是一个常量。所以,如果你尝试这样做

static int j = N; /* ERROR */

you will get the same error: an attempt to initialize a static object with a non-constant.

你会得到同样的错误:尝试用非常量来初始化一个静态对象。

This is the reason why, in C language, we predominantly use #defineto declare named constants, and also resort to #defineto create named aggregate initializers.

这就是为什么在 C 语言中,我们主要使用#define声明命名常量,也#define使用创建命名聚合初始化器的原因。

回答by R Samuel Klatchko

It's a limitation of the language. In section 6.7.8/4:

这是语言的限制。在第 6.7.8/4 节中:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

具有静态存储持续时间的对象的初始值设定项中的所有表达式应为常量表达式或字符串文字。

In section 6.6, the spec defines what must considered a constant expression. No where does it state that a const variable must be considered a constant expression. It is legal for a compiler to extend this (6.6/10 - An implementation may accept other forms of constant expressions) but that would limit portability.

在第 6.6 节中,规范定义了必须将什么视为常量表达式。没有哪里声明必须将 const 变量视为常量表达式。编译器扩展这个 ( 6.6/10 - An implementation may accept other forms of constant expressions)是合法的,但这会限制可移植性。

If you can change my_fooso it does not have static storage, you would be okay:

如果你可以改变my_foo它没有静态存储,你会没事的:

int main()
{
    foo_t my_foo = foo_init;
    return 0;
}

回答by achoora

Just for illustration by compare and contrast The code is from http://www.geeksforgeeks.org/g-fact-80//The code fails in gcc and passes in g++/

只是为了通过比较和对比来说明代码来自http://www.geeksforgeeks.org/g-fact-80//代码在 gcc 中失败并在 g++ 中通过/

#include<stdio.h>
int initializer(void)
{
    return 50;
}

int main()
{
    int j;
    for (j=0;j<10;j++)
    {
        static int i = initializer();
        /*The variable i is only initialized to one*/
        printf(" value of i = %d ", i);
        i++;
    }
    return 0;
}

回答by valenumr

This is a bit old, but I ran into a similar issue. You can do this if you use a pointer:

这有点旧,但我遇到了类似的问题。如果使用指针,则可以执行此操作:

#include <stdio.h>
typedef struct foo_t  {
    int a; int b; int c;
} foo_t;
static const foo_t s_FooInit = { .a=1, .b=2, .c=3 };
// or a pointer
static const foo_t *const s_pFooInit = (&(const foo_t){ .a=2, .b=4, .c=6 });
int main (int argc, char **argv) {
    const foo_t *const f1 = &s_FooInit;
    const foo_t *const f2 = s_pFooInit;
    printf("Foo1 = %d, %d, %d\n", f1->a, f1->b, f1->c);
    printf("Foo2 = %d, %d, %d\n", f2->a, f2->b, f2->c);
    return 0;
}

回答by xjtuecho

gcc 7.4.0 can not compile codes as below:

gcc 7.4.0 无法编译如下代码:

#include <stdio.h>
const char * const str1 = "str1";
const char * str2 = str1;
int main() {
    printf("%s - %s\n", str1, str2);
    return 0;
}

constchar.c:3:21: error: initializer element is not constant const char * str2 = str1;

constchar.c:3:21: 错误:初始化元素不是常量 const char * str2 = str1;

In fact, a "const char *" string is not a compile-time constant, so it can't be an initializer. But a "const char * const" string is a compile-time constant, it should be able to be an initializer. I think this is a small drawback of CLang.

实际上,“const char *”字符串不是编译时常量,因此它不能是初始化程序。但是一个“const char * const”字符串是一个编译时常量,它应该能够作为一个初始化器。我认为这是 CLang 的一个小缺点。

A function name is of course a compile-time constant.So this code works:

函数名当然是编译时常量。所以这段代码有效:

void func(void)
{
    printf("func\n");
}
typedef void (*func_type)(void);
func_type f = func;
int main() {
    f();
    return 0;
}