【问题标题】:GCC missing braces around initializer [duplicate]GCC 在初始化器周围缺少大括号
【发布时间】:2012-07-18 23:42:59
【问题描述】:

我在下面的 C 中有这个结构,我想将其初始化为零。如何摆脱缺少大括号的警告?

typedef struct {
    uint32_t incoming[FRAME_TYPE_MAX];
    uint32_t outgoing[FRAME_TYPE_MAX];
    uint32_t timeouts;
    uint32_t crc_errors;
} pkt_t;

static pkt_t stats = {0};

【问题讨论】:

  • 使用{0} 作为初始化器是一个非常有用的习惯用法。它对 any 类型有效,并将所有成员初始化为零(0、0.0 或 NULL)。不幸的是 gcc 不承认这一点。

标签: c gcc gcc-warning


【解决方案1】:

这是 GCC 错误 #53119:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119

如果您希望看到它已修复,请在错误报告中发布后续内容,表明这对您来说是个问题。

【讨论】:

  • 似乎可以重新排序结构成员,以便第一个成为标量,警告消失。当您需要重新解释时,这不是一个选项,例如内存映射设备寄存器,但在大多数情况下,这可能被视为一种解决方法。
  • 这可能会也可能不会,但这绝对不是一个合适的解决方案。
  • 这不是解决方案。在 GCC 错误修复之前,这是一个临时解决方法
  • 据报道,GCC 错误已得到修复。不确定修复程序是否已发布。
  • @DevNull:它不会影响代码的编译方式。相反,它会影响代码的编写方式,即人们要么编写不可移植的构造 ({}),要么编写“正确”数量的嵌套级别以匹配特定版本的结构定义,以使警告消失。导致人们编写更糟糕的代码来抑制警告的警告是编译器可能拥有的一些最有害的警告。
【解决方案2】:

由于结构中的第一个成员是您需要的数组:

static pkt_t stats = {{0}};

外大括号用于结构,内大括号用于数组。但是,还有许多其他方法可以给这只猫剥皮。 (例如,静态已经初始化为零)

【讨论】:

【解决方案3】:

如果是全局变量或局部静态变量,它会自动初始化。所以,简单地说:

static pkt_t stats;

【讨论】:

  • 好收获。这也将(标准未指定,但这是它在所有实际情况下的工作方式)将对象放入 bss 而不是数据中,从而减少可执行文件的大小。
【解决方案4】:

一种方法是初始化大括号内结构的每个成员,而不是依赖于隐式零填充。对于数组成员,您需要另一个可能导致警告的 {}。另一种方法是禁用警告,但不建议这样做,因为它也可以捕获合法的错误。

【讨论】:

  • +1 不禁用警告,甚至不建议这样做。其实开启-Werror :-)
  • 禁用警告是正确的解决方法。警告是错误的,并且标记了正确的代码,基本上没有任何东西会标记实际上是一个错误......
  • 可以仅针对该行代码禁用警告,从而确保警告在项目的其余部分保持有效。
【解决方案5】:

设置这个 gcc 编译器标志: -Wno-missing-braces

【讨论】:

    【解决方案6】:
    #define FRAME_TYPE_MAX 3
    
    typedef struct {
        uint32_t incoming[FRAME_TYPE_MAX];
        uint32_t outgoing[FRAME_TYPE_MAX];
        uint32_t timeouts;
        uint32_t crc_errors;
    } pkt_t;
    
    static pkt_t stats1= { .incoming={5,6,20},
                           .outgoing={0,0,0},
                           .timeouts=0,
                           .crc_errors=0
                           };
    
    static pkt_t stats2= { {5,6,20},
                           {0,0,0},
                           0,
                           0
                           };
    
    static pkt_t stats3= {{0}};
    
    pkt_t stats4 ;   // global
    
    
    int main(void)
    {
    
        stats1.incoming[0]= 35;
        stats1.timeouts=25;
        stats2.incoming[2]=10;  
        stats3.outgoing[2]=10;  
        stats4.timeouts=10;
        for (;;);
        }
    

    【讨论】:

      【解决方案7】:

      如果您仍然对忽略此错误警告的 g​​cc 版本感到高兴,那么在问题中使用这样的结构,您可以通过一些简单的重组来避免这个问题:

      typedef struct {
          uint32_t timeouts;
          uint32_t crc_errors;
          uint32_t incoming[FRAME_TYPE_MAX];
          uint32_t outgoing[FRAME_TYPE_MAX];
      } pkt_t;
      
      static pkt_t stats = {0};
      

      【讨论】:

        【解决方案8】:

        来自“信息 gcc”

        作为 GNU 扩展,GCC 允许通过复合文字初始化具有静态存储持续时间的对象(这在 ISO C99 中是不可能的,因为初始化器不是常量)。如果复合文字和对象的类型匹配,则它的处理方式就像对象仅使用括号括起来的列表进行初始化一样。复合文字的初始化列表必须是常量。如果正在初始化的对象具有未知大小的数组类型,则大小由复合字面量大小决定。

         static struct foo x = (struct foo) {1, 'a', 'b'};
         static int y[] = (int []) {1, 2, 3};
         static int z[] = (int [3]) {1};
        

        以上几行等价于以下内容:

         static struct foo x = {1, 'a', 'b'};
         static int y[] = {1, 2, 3};
         static int z[] = {1, 0, 0};
        

        您可以组合这些初始化程序以允许对数组进行特定于 gcc 的初始化,而无需指定数组中的每个元素。或者...您可以设置一个标志并在运行时在必要时对其进行初始化,或者...您可以发现变量是否在 BSS 中并且可能会自动归零(这是在函数的堆栈上还是在全局内存中)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-12-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-24
          相关资源
          最近更新 更多