有人可以解释这两个initiliazers之间的区别吗?

时间:2017-07-10 19:06:11

标签: c gcc gnu99

我想知道是否有人可以提供以下两段代码之间差异的详细,简单的解释。鉴于以下定义:

intellisense

有什么区别:

  • typedef struct { stuff; stuff_2; } variable_t;
  • variable_t my_variable;

如果我执行第一个,然后从未完全初始化它,为什么编译器不会抛出错误?

注意:我正在使用variable_t my_variable = {};进行编译,因此第二个是有效的,最终解决了我遇到的问题。我想知道为什么。

2 个答案:

答案 0 :(得分:2)

它取决于你放置相应变量定义的位置,它似乎也取决于使用的编译器。

自动存储时间

让我们讨论当变量具有自动存储持续时间时的差异(如果将其置于函数或块范围内并且没有static关键字,则会出现这种情况):

void someFunction() {
   variable_t my_variable;       // (1)
   variable_t my_variable = {};  // (2)
}

(1)表示没有显式初始化的变量定义。根据这个online C standard draft,它的价值是不确定的:

  

如果未初始化具有自动存储持续时间的对象   显然,它的价值是不确定的。

(2)是一个变量定义,通过没有指示符的初始化列表显式初始化,即不通过名称将值与成员相关联,而只是通过值的顺序(参见6.7.9 p17..21)。

有趣的段落是6.7.9 p21,它指出如果初始化列表的条目数少于结构成员的数量,则根据静态存储持续时间的初始化规则初始化成员(即0NULL,如后面所述):

  

如果括号括起的列表中的初始值设定项少于此值   是聚合的元素或成员,......,其余部分   aggregate应该与对象一样隐式初始化   有静态存储时间。

所以看来如果你写variable_t my_variable = {},那么所有成员都会被初始化为0NULL

但是,正如aschepler在评论中所提到的,C initialization list grammar指出初始化列表不能为空(参见cppreference.com):

  

...初始化程序必须是非空的,括号括起来的,   逗号分隔的成员初始值设定项列表

因此,根据标准,C中的初始化列表至少需要一个条目;在我的XCode8.3环境中使用-std=gnu99进行测试时,似乎支持一个空的初始化列表,但我知道这不是一个有效的引用。因此,为了安全而不依赖于特定的编译器扩展,您应该写一下:

   variable_t my_variable = {0};  

静态存储时间

在文件范围内,您的变量定义将具有静态存储持续时间,然后应用其他规则(参见6.7.9 (10)):

  

(10)...如果具有静态或线程存储持续时间的对象是   没有明确初始化,那么:

     
      
  • 如果它有指针类型,则将其初始化为空指针;
  •   
  • 如果它有算术类型,则初始化为(正数或无符号)零;
  •   
  • 如果是聚合,则根据这些规则初始化(递归)每个成员,并将任何填充初始化为零位;
  •   
  • 如果是联合,则根据这些规则初始化(递归)第一个命名成员,并初始化任何填充   为零位;
  •   
     

...

     

(21)如果括号括起的列表中的初始值设定项少于聚合的元素或成员,则聚合的其余部分应与具有静态存储持续时间的对象隐式初始化。 / p>

所以,如果你写...

#include <stdio.h>
variable_t my_variable;       // (1)
variable_t my_variable = {};  // (2)

然后(1)和(2)实际产生相同的结果,因为对于未明确初始化的变量(1),段落(10)适用,并且对于明确但空的初始化变量(2),根据段落(21) ),每个成员都回到(10)的初始化规则。

同样,编译器可能不支持如上所述的空的初始化列表。

希望它有所帮助(因为它打字很多:-))

答案 1 :(得分:-2)

宣布:

variable_t my_variable;           // a variable_t that is uninitialized

variable_t my_variable = {};      // a variable_t initialized with zeroes.

请注意,对于在文件范围内声明的变量,这并不重要,因为数据是 - 在程序启动之前通常归零。

在堆栈上使用,第二行有效地用零填充my_variables。就像打电话给:

一样

memset(&variable, 0, sizeof(variable));

这是有效的,因为在C中,您可以使用struct复制=

这是计算机肯定会赢的小游戏。

struct A { /*...*/ };

void main() 
{
   A a;  // random
   A b = {};
   if (memcmp(&a, &b, sizeof(A)) == 0)
   {
       printf("You win\n");
       return;
   }

   a = b;
   if (memcmp(&a, &b, sizeof(A)) == 0)
   {
       printf("I win\n");
   }
}