&引用;初始化器元素不是常量;使用静态常量变量-有时-编译器设置时在C中出错?

&引用;初始化器元素不是常量;使用静态常量变量-有时-编译器设置时在C中出错?,c,gcc,C,Gcc,我之所以发布这篇文章,是因为我在别处找不到合适的答案,而不是因为以前没有人问过类似的问题 项目可以通过以下方式编译: #include <stdint.h> void foo(void) { if (bar) { static const uint8_t ConstThing = 20; static uint8_t StaticThing = ConstThing; //... } } #包括 无效foo(无效) {if(bar) {

我之所以发布这篇文章,是因为我在别处找不到合适的答案,而不是因为以前没有人问过类似的问题

项目可以通过以下方式编译:

#include <stdint.h>
void foo(void)
{  if (bar)
   {  static const uint8_t ConstThing = 20;
      static uint8_t StaticThing = ConstThing;
        //...
    }
}
#包括
无效foo(无效)
{if(bar)
{静态常数uint8_t ConstThing=20;
静态uint8\u t statisthing=常数;
//...
}
}
但是克隆的项目却没有,抛出了上述错误。看起来我们还没有完全克隆编译器设置/警告级别等,但是现在找不到区别

使用arm none eabi gcc(4.7.3)和-std=gnu99。为Kinetis编写

如果有人知道在同一个编译器中,哪些设置控制了合法和非法的情况,我洗耳恭听。提前感谢。

发现了差异

  • 如果优化为-O0,则不会编译
  • 如果优化是-OS,那么它就是
我猜它会产生“你所要求的,一种更好的方式”,并修复它

没想到会这样。谢谢大家的意见。

将我的一些评论转化为答案

在标准C中,ConstThing是一个常量整数,但不是一个整数常量,您只能用整数常量初始化静态变量。C++中的规则是不同的,适合不同的语言。 C11规定:

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

定义整数常量

定义常量表达式

…我不确定我是否理解“常量整数”和“整数常量”之间的区别

请注意,
consthing
不是§6.4.4.1中定义的整数常量之一-因此,不管它是什么,它都不是整数常量。由于它是一个
常量
-限定的
int
,因此它是一个常量整数,但与整数常量不同。有时,标准的语言令人惊讶,但通常非常精确

问题中的代码由GCC 4.7.3编译,显然使用
-O0
编译会触发错误,并使用
-Os
编译(
-OS
在问题中被要求,但在标准GCC中不受支持-它要求
-O
的可选参数为非负整数,或
s
g
fast
)不会。根据优化级别对代码的有效性有不同的看法不是一种舒适的体验——更改优化不应该改变代码的含义

所以,结果依赖于编译器,而不是C标准所要求的。只要你知道你在限制可移植性(理论上,即使不是在实践中),那也没关系。如果你没有意识到你正在违反标准规则,如果可移植性很重要,那么你就有“不要做”的问题就我个人而言,我不会冒险——代码应该在编译时进行优化或不进行优化,并且不应该依赖于特定的优化标志。否则它就太脆弱了

话虽如此,如果有什么安慰的话,GCC 10.2.0和Apple clang 11.0.0版(clang-1100.0.33.17)都接受带有选项的代码

gcc -std=c11 -pedantic-errors -pedantic -Werror -Wall -Wextra -O3 -c const73.c
任何
-O0
-O1
-O2
-O3
-Os
-Og
-Ofast
。这让我感到惊讶-我认为不应该在迂腐的(严格的)标准一致模式下接受它(这与
-std=gnu11
不同;然后扩展被视为有效)。即使在
-Weverything
编译中添加
-Weverything
也不会触发错误。这确实让我感到惊讶。这些选项旨在诊断超出标准的扩展,但并不完全成功。请注意,GCC 4.7.3非常旧;它已发布。此外,GCC 7.2.0和v7.3.0还抱怨未发布的代码r
-O0
,但不在
-Os
-O1
-O2
-O3
等下,而GCC 8.x.0、9.x.0和10.x.0不在其中

extern int bar;
extern int baz;
extern void foo(void);

#include <stdio.h>
#include <stdint.h>

void foo(void)
{
    if (bar)
    {
        static const uint8_t ConstThing = 20;
        static uint8_t StaticThing = ConstThing;
        baz = StaticThing++;
    }
    if (baz)
        printf("Got a non-zero baz (%d)\n", baz);
}

<编译>没有任何编译器在任何优化级别接受这个值。

我不认为代码> const <代码>限定的VAR是C中的编译时间常数。在标准C中,<代码> conthest是一个常量整数,但不是整数常量,只能初始化具有整数常数的代码>静态< /代码>变量。C++中的规则是不同的。C11:具有静态或线程存储持续时间的对象的初始值设定项中的所有表达式都应该是常量表达式或字符串文字Jonathan Leffler谢谢,我很确定你是对的,但我不确定我是否理解常量整数和整数常量之间的区别……哈哈哟你的编辑比我快:)感谢第6.4.4.1节整数常量(之前链接)中整数常量的定义。请注意,
consthing
不是§6.4.4.1中定义的整数常量之一-因此,不管它是什么,它都不是整数常量。由于它是一个
常量
-限定的
int
,因此它是一个常量整数,但与整数常量不同。有时,标准的语言令人惊讶,但它通常非常精确。这取决于编译器,而不是C标准所要求的。只要你知道你在限制可移植性(理论上,即使不是在实践中),那就没关系。如果你没有意识到你正在违反标准规则,如果可移植性很重要,那么你就会遇到“不要做”的问题。就个人而言,我不会冒险——代码应该编译时进行优化或不进行优化,并且不应该依赖于特定的优化标志。否则它太脆弱了。你是说如果其他东西都一样的话
extern int bar;
extern int baz;
extern void foo(void);

#include <stdio.h>
#include <stdint.h>

extern const uint8_t ConstThing; // = 20;

void foo(void)
{
    if (bar)
    {
        static uint8_t StaticThing = ConstThing;
        baz = StaticThing++;
    }
    if (baz)
        printf("Got a non-zero baz (%d)\n", baz);
}