2

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

typedef struct {
    stuff;
    stuff_2;
} variable_t;

有什么区别:

  • variable_t my_variable;
  • variable_t my_variable = {};

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

注意:我正在编译gcc -std=gnu99,所以第二个是有效的,并且最终解决了我遇到的问题。我想知道为什么。

4

2 回答 2

2

这在一定程度上取决于您放置相应变量定义的位置,而且似乎也取决于使用的编译器。

自动存储时间

让我们讨论一下变量具有自动存储持续时间时的区别(如果您将它放在函数或块范围内并且没有static关键字):

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

(1) 表示没有显式初始化的变量定义。根据这个在线 C 标准草案,它的价值是不确定的:

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

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

有趣的段落是6.7.9 p21,它指出如果初始化器列表的条目少于结构成员的数量,则根据静态存储持续时间的初始化规则对成员进行初始化(即 to0NULL稍后解释):

如果大括号括起来的列表中的初始化程序少于聚合的元素或成员,...,则聚合的其余部分应隐式初始化,与具有静态存储持续时间的对象相同。

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

但是,正如 aschepler 在评论中提到的,C 初始化列表语法规定初始化列表不能为空(参见cppreference.com):

...初始化程序必须是成员的初始化程序的非空、大括号括起来、逗号分隔的列表

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

   variable_t my_variable = {0};  

静态存储时间

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

(10) ... 如果具有静态或线程存储持续时间的对象未显式初始化,则:

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

...

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

所以如果你写...

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

那么(1)和(2)实际上产生相同的结果,因为对于未显式初始化的变量(1),第(10)段适用,而对于显式但为空的初始化变量(2),根据第(21)段,每个member 回退到 (10) 的初始化规则。

同样,编译器可能不支持上面讨论的空初始化列表。

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

于 2017-07-10T21:28:34.323 回答
-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 中,您可以复制structusing =

这是一个电脑肯定会赢的小游戏。

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");
   }
}
于 2017-07-10T19:13:46.147 回答