3

如果我有一个常见的 linux 结构,例如:

struct sockaddr_in
{
  sa_family_t    sin_family;   
  in_port_t      sin_port;     
  struct in_addr sin_addr;     

  unsigned char  __pad[__SOCK_SIZE__ - sizeof(short int)
                        - sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero        __pad

我执行聚合初始化:

struct sockaddr_in my_addr = { 0 };

为什么这会将每个成员初始化为 0?

我的意思是:文档说:

如果初始化器子句的数量少于成员的数量或初始化器子句完全为空,则剩余的成员由它们的大括号或等号初始化器初始化,如果在类定义中提供,否则 (C++14 起)通过空列表执行值初始化。

为了简单起见:为什么这段代码打印 0?

struct sockaddr_in my_addr = {2, 2}; // initialize sin_family and sin_port to 2, everything else value-initialized

my_addr = {0};

std::cout << my_addr.sin_port; // Why is this 0?
4

2 回答 2

2

这在草案 C++14 标准部分8.5.4 List-initialization中有介绍,其中说:

类型 T 的对象或引用的列表初始化定义如下:

包括:

如果 T 是聚合,则执行聚合初始化 (8.5.1)。

并具有以下示例:

struct S2 {
    int m1;
    double m2, m3;
}
S2 s21 = { 1, 2, 3.0 }; // OK
S2 s22 { 1.0, 2, 3 }; // error: narrowing
S2 s23 { }; // OK: default to 0,0,0

8.5.1 聚合它说:

如果列表中的初始化子句少于聚合中的成员,则每个未显式初始化的成员都应从其大括号或相等初始化器中初始化,或者,如果没有大括号或相等初始化器,则从空初始化列表(8.5.4)。[ 例子:

struct S { int a; const char* b; int c; int d = b[a]; };
S ss = { 1, "asdf" };

用 1 初始化 ss.a,用“asdf”初始化 ss.b,用 int{} 形式的表达式的值(即 0)初始化 ss.c

请注意,8.5.4在 C++11 中略有不同,它说:

类型 T 的对象或引用的列表初始化定义如下:

  • 如果初始值设定项列表没有元素并且 T 是具有默认构造函数的类类型,则该对象是值初始化的。

  • 否则,如果 T 是一个聚合,则执行聚合初始化 (8.5.1)。

于 2014-10-08T11:52:56.473 回答
1

为什么这会将每个成员初始化为 0?

因为这就是 C 在初始化结构时所做的事情,而 C++ 对聚合初始化也是如此,以实现兼容性。

C 这样做是因为它更方便(它通常是你想要的成员,你没有给出明确的值)并且更安全(它不会留下危险的未初始化变量)。

如果你真的希望结构的其他成员保持未初始化,你可以这样做:

struct sockaddr_in s; // entirely uninitialized
s.sin_family = 0;     // only initialize one member
于 2014-10-08T12:07:05.520 回答