C “错误”;初始值设定项元素不是常量;尝试使用常量初始化变量时

C “错误”;初始值设定项元素不是常量;尝试使用常量初始化变量时,c,initialization,C,Initialization,我在下面程序的第6行(将我的_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; } 请记住,这是我正在处理的一个更大、多文件项目的简化版本。目标是在对象文件中有一个常量,多个文件可以使用该常

我在下面程序的第6行(将我的_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;
}
请记住,这是我正在处理的一个更大、多文件项目的简化版本。目标是在对象文件中有一个常量,多个文件可以使用该常量初始化状态结构。由于它是一个资源有限的嵌入式目标,并且结构没有那么小,所以我不需要源代码的多个副本。我不想使用:

#define foo_init { 1, 2, 3 }
我还试图编写可移植代码,所以我需要一个有效的C89或C99解决方案

这与对象文件中的组织有关吗?初始化的变量进入一个组织并通过复制第二个组织的内容来初始化


也许我只需要改变我的策略,让一个初始化函数在启动时完成所有的拷贝。在C语言中,除非有其他想法,否则具有静态存储持续时间的对象必须使用常量表达式或包含常量表达式的聚合初始值设定项进行初始化

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

此外,在C语言中,术语“常量”指的是文字常量(如
1
'a'
0xFF
等)、枚举成员以及诸如
sizeof
等运算符的结果。常量限定对象(任何类型)在C语言术语中都不是常量。它们不能用于具有静态存储持续时间的对象的初始值设定项中,无论其类型如何

例如,这不是一个常数

const int N = 5; /* `N` is not a constant in C */
< > >代码> N< /C>是C++中的常量,但如果你尝试做< /P>,那么它不是C.中的常量。
static int j = N; /* ERROR */
您将得到相同的错误:尝试使用非常量初始化静态对象


这就是为什么在C语言中,我们主要使用
#define
来声明命名常量,并且还使用
#define
来创建命名聚合初始值设定项的原因。

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

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

在第6.6节中,规范定义了必须视为常量表达式的内容。不,它在哪里声明常量变量必须被视为常量表达式。编译器对此进行扩展是合法的(
6.6/10-实现可以接受其他形式的常量表达式),但这会限制可移植性

如果您可以更改my_foo的
my_foo
,使其不具有静态存储,您就可以:

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

只是为了通过比较和对比来说明 代码来自 /代码在gcc中失败,并在g中通过++/

#包括
int初始值设定项(void)
{
返回50;
}
int main()
{
int j;

对于(j=0;j这有点旧,但我遇到了类似的问题。如果使用指针,您可以执行此操作:

#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;
}
#包括
typedef struct foo\u t{
int a;int b;int c;
}富特;
静态常量foo_t s_FooInit={.a=1、.b=2、.c=3};
//还是指针
静态常量foo_t*常量s_pFooInit=(&(const foo_t){.a=2、.b=4、.c=6});
int main(int argc,字符**argv){
常量foo\u t*常量f1=&s\u FooInit;
常数foo_t*常数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);
返回0;
}

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;
}

我在代码中遇到了如下错误:

int A = 1;
int B = A;
解决方法是将其更改为此

int A = 1;
#define B A

编译器将内存中的一个位置分配给一个变量。第二个正在尝试将第二个变量分配给与第一个相同的位置-这没有任何意义。使用宏预处理器解决了这个问题。

2021:对于因为STM32 MCU上的
arm none eabi gcc.exe
编译错误而到达此职位的人:
将工具链更改为
gnu-tools-for-stm32.9-2020-q2-update

GCC V8.1+支持嵌套常量初始值设定项,下面的代码将被编译

const int a=1;
常数int b=a+1;
typedef struct foo\u t{
INTA、b、c;
}富特;
const foo_t foo_init={1,2,3};
foo_t my_foo=foo_init;
int main()
{
返回0;
}
gnu-tools-for-stm32.7-2018-q2-update
中的
arm-none-eabi-gcc.exe
基于
gcc v7.3.1
,上面的代码不会编译!但是
gnu-tools-for-stm32.9-2020-q2-update
使用
gcc v9.3.1
并将编译

有关更多信息,请参见以下内容:



+5的解释很好,但令人惊讶的是,这个程序在ideone上编译得很好:。是编译器错误还是编译器扩展?Thanks@meet:我不知道ideone在幕后使用了哪些编译器选项组合,但它们的结果往往难以描述。我尝试在Coliru()上编译此代码不管我使用的是什么C语言方言设置,它都得到了预期的错误。我在GCC的网站上没有看到类似的东西作为C语言扩展列出。换句话说,我不知道它是如何以及为什么用ideone编译的。即使它作为语言扩展编译,也应该用C生成诊断消息。
enum{N=5};
是一种不受欢迎的声明常量的方式,而不必求助于
#define
@PravasiMeet“ideone”只是没有显示编译器生成的许多诊断消息,因此它不是一个确定代码是否正确的好网站。我发现了一些有趣的事情。如果ptr是在函数中定义的静态指针,这就是错误:
static int*ptr=malloc(sizeof(int)*5);
但这不是一个错误:
静态int*ptr;ptr=malloc(sizeof(int)*5);
:我没有看到带有
int A = 1;
int B = A;
int A = 1;
#define B A