C和C ++:自动结构的部分初始化


71

例如,如果somestruct有三个整数成员,我一直认为可以在C(或C ++)函数中执行此操作:

somestruct s = {123,};

第一个成员将初始化为123,后两个成员将初始化为0。我经常对自动数组执行相同的操作,编写 int arr[100] = {0,};该函数,以便将数组中的所有整数都初始化为零。


最近,我读了《GNU C参考手册》中:

如果不初始化结构变量,则效果取决于它是否具有静态存储(请参见存储类说明符)。如果是,则将整数类型的成员初始化为0,将指针成员初始化为NULL;否则,将其初始化为NULL。否则,结构成员的值是不确定的。


有人可以告诉我有关部分自动结构和自动数组初始化的C和C ++标准怎么说?我在Visual Studio中完成上面的代码没有问题,但是我想与gcc / g ++以及其他编译器兼容。谢谢


1
对于问题的C ++部分,您可能会对此问题感兴趣。
比约恩·波莱克斯(BjörnPollex)

Answers:


103

链接的gcc文档没有提到部分初始化,而只是谈论(Complete)InitializationNo Initialization

什么是部分初始化?

这些标准没有定义对象的部分初始化,无论是完全初始化还是没有初始化。部分初始化是一种非标准术语,通常是指您提供了一些初始化器但未全部提供的情况,即:初始化器少于数组的大小或要初始化的结构元素的数量。

例:

int array[10] = {1,2};                    //Case 1:Partial Initialization

什么是(完全)初始化或没有初始化?

初始化是指在创建变量的同时为其提供一些初始值。即:在同一代码语句中。

例:

int array[10] = {0,1,2,3,4,5,6,7,8,9};    //Case 2:Complete Initialization
int array[10];                            //Case 3:No Initialization

引用的段落描述了的行为Case 3

Case 1标准已很好地定义了有关部分初始化()的规则,这些规则不依赖于要初始化的变量的存储类型。
AFAIK,所有主流编译器均100%遵守这些规则。


有人可以告诉我有关部分自动结构和自动数组初始化的C和C ++标准怎么说?

C和C ++标准保证,即使整数数组位于自动存储中,并且括号括起来的列表中的初始化程序较少,也必须将未初始化的元素初始化为0

C99标准6.7.8.21

如果用大括号括起来的列表中的初始化程序少于集合中的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符少于该数组中的元素,则该集合的其余部分应与具有静态存储持续时间的对象隐式初始化相同。


在C ++中,规则的声明略有不同。

C ++ 03标准8.5.1汇总
第7段:

如果列表中的初始化程序少于聚合中的成员,则每个未显式初始化的成员都应进行值初始化(8.5)。[例:

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

初始化ss.a1ss.b"asdf",和ss.c与所述形式的表达的值int(),即,0。]

在定义值初始化的同时,
C ++ 03 8.5初始化程序
第5段:

要对类型为T的对象进行值初始化意味着:
—如果T是具有用户声明的构造函数(12.1)的类类型(第9节),则将调用T的默认构造函数(如果T初始化为错误格式,没有可访问的默认构造函数);
—如果T是一个没有用户声明的构造函数的非联合类类型,则T的每个非静态数据成员和基类组件都将被值初始化;
—如果T是数组类型,则每个元素都进行值初始化;
—否则,该对象将被零初始化


感谢您提供详尽的答案。关于值初始化,您是否偶然知道C ++中DWORD()形式的表达式是否保证为0?Björn在我的问题上作了评论,并链接了一个关于值初始化的问题,但是我不清楚Visual Studio是否支持它,因为它是C ++ 98,而不是C ++ 03。

@test:AFAIK,在C ++ 98中只有两种类型的初始化,零初始化默认初始化,C ++ 03添加了值初始化DWORD()在C ++ 98中将被评估为零初始化
Alok保存2012年

2
then the uninitialized elements must be initialized to 0.嗯...不 它们没有初始化为零,而是初始化为,initialized implicitly the same as objects that have static storage duration对于所有标准C类型,该值可能为零,当前可能为零,但是该标准未明确要求零。很抱歉,但如果您说出一些话然后引用一个标准说其他话(即使您说的话可能都正确),这有点奇怪。
梅基'17

@Mecki:好点。答案过于简单了。
Alok保存

17

在C语言中,对象永远不会部分初始化-如果它们的任何部分都被初始化,则整个对象(以及所有子对象都将递归地)被初始化。如果未提供显式初始化程序,则将元素初始化为“适当类型的零”。

您问题中的引用是指何时完全忽略了整个对象的初始化程序,而不是指子对象缺少初始化程序的时候。例如,假设arr具有自动存储期限,则可以这样:

int arr[100] = { 123 };

初始化arr[0]123与所有其他元素arr0。鉴于此:

int arr[100];

保留所有arr未初始化的元素。这是引用的后一种情况。


在这种情况下,int arr [100] = {123}; 是否将数组arr的其余所有其他元素初始化为ASCII 0或数字0?
Radha Gogia

@RadhaGogia:数字0
CAF

有什么方法可以检查出该值以确认它不是ASCII 0,因为当我执行%c时,它不打印任何内容,所以我想知道如何确认编译器是否用null(ASCII 0)或数字填充其余条目。 0?
Radha Gogia

@RadhaGogia:使用进行打印时,数字/整数零ASCII空字符%c
caf

'\0'为空(即(char)0);'0'是ASCII 0(即(char)48)。
imallett

4

最新的gcc版本还允许同时“部分”初始化和zeromem:

typedef struct{
  int a,b,c;
}T;

T s = {0, .b=5};

struct成员现在将具有以下值: a=0, b=5, c=0

我没有其他编译器是否允许的信息:p


7
这是C99功能,不是特别新。它称为“指定的初始值设定项”,受到广泛支持。但是,它不是C ++功能。C ++使用构造函数。
MSalters
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.