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

loo*_*oop 67 c c++

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

somestruct s = {123,};
Run Code Online (Sandbox Code Playgroud)

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


最近我在GNU C参考手册中读到:

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


有人可以告诉我C和C++标准对部分自动结构和自动数组初始化的看法吗?我在Visual Studio中执行上述代码没有问题,但我希望与gcc/g ++兼容,也可能与其他编译器兼容.谢谢

Alo*_*ave 94

链接的gcc文档没有谈到部分初始化它只谈到(完成)初始化没有初始化.

什么是部分初始化?

标准没有定义对象的部分初始化,要么是完全初始化,要么是无初始化.部分初始化是一种非标准术语,通常指的是您提供一些初始值设定项但不是全部的初始值,即:初始化程序的数量少于数组的大小或初始化的结构元素的数量.

例:

int array[10] = {1,2};                    //Case 1:Partial Initialization
Run Code Online (Sandbox Code Playgroud)

什么是(完整)初始化或无初始化?

初始化意味着在创建变量的同时为创建的变量提供一些初始值.即:在相同的代码语句中.

例:

int array[10] = {0,1,2,3,4,5,6,7,8,9};    //Case 2:Complete Initialization
int array[10];                            //Case 3:No Initialization
Run Code Online (Sandbox Code Playgroud)

引用的段落描述了行为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" };
Run Code Online (Sandbox Code Playgroud)

初始化ss.awith 1,ss.bwith "asdf"ss.cwith表达式的表达式int(),即0.]

值初始化定义于,
C++ 03 8.5 Initializers
Para 5:

值初始化类型的物体T是指:
-如果T是一个类型(第9节)与用户声明的构造(12.1),然后对T中的默认构造函数被调用(以及初始化是形成不良的如果T没有可访问的默认构造函数);
- 如果T是没有用户声明的构造函数的非联合类类型,则T的每个非静态数据成员和基类组件都是值初始化的;
- 如果T是数组类型,则每个元素都是值初始化的;
- 否则,对象被零初始化

  • `那么未初始化的元素必须初始化为 0。` 嗯...不。它们没有初始化为零,而是“与具有静态存储持续时间的对象隐式初始化相同”,它可能为零,目前对于所有标准 C 类型可能为零,但标准没有明确要求为零。很抱歉吹毛求疵,但如果你说一些话然后引用一个说其他话的标准,这有点奇怪(即使你说的可能都是对的)。 (3认同)
  • @codosopher 如果你这样做 `int ar[100];`,`ar` 通常根本不会初始化并且具有随机值。如果你这样做 `int ar[100]; ar[5] = 0;`那么只有`ar[5]`被初始化为0,其余的仍然是随机的。如果使用 int ar[100] = { 0 };`,则 ar[0]` 被初始化为 0,其余部分获取静态变量的值,该值可能为 0,但不一定为 0。将数组初始化为全零的唯一符合标准的方法是 `int ar[100]; memset(ar, 0, sizeof(ar));` (2认同)

caf*_*caf 16

在C中,对象永远不会被部分初始化 - 如果它们的任何部分被初始化,则初始化整个对象(以及递归的所有子对象).如果没有提供显式初始化器,则将元素初始化为"适当类型的零".

您的问题中的引用是指完全遗漏整个对象的初始化程序,而不是指子对象缺少初始化程序时.例如,假设arr具有自动存储持续时间,那么:

int arr[100] = { 123 };
Run Code Online (Sandbox Code Playgroud)

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

int arr[100];
Run Code Online (Sandbox Code Playgroud)

留下arr未初始化的每一个元素.引用的是后一种情况.


roc*_*441 5

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

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

T s = {0, .b=5};
Run Code Online (Sandbox Code Playgroud)

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

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

  • 这是C99功能,不是特别新。它称为“指定的初始值设定项”,受到广泛支持。但是,它不是C ++功能。C ++使用构造函数。 (4认同)