为什么编译器会抛出此警告:“缺少初始化器”?结构没有初始化吗?


79

我正在为程序创建某种前端。要启动该程序,我使用调用CreateProcess(),它除其他外还接收指向STARTUPINFO结构的指针。要初始化我曾经做过的结构:

STARTUPINFO startupInfo = {0}; // Or even '\0'.
startupInfo.cb = sizeof(startupInfo);

当使用启用了这些警告的GCC编译程序时,-Wall -Wextra它向我发出警告,指出缺少指向第一行的初始化程序。

warning: missing initializer
warning: (near initialization for 'startupInfo.lpReserved')

所以我最终做了:

STARTUPINFO startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);

这样,编译器就不会发出任何警告。问题是,这些初始化结构的方式之间有什么区别?使用第一种方法,是否不初始化结构?您会推荐哪一个?


1
警告只是:警告。在此特定场合可以忽略此特定警告。在以下情况下,编译器会发出警告以帮助您:struct struct_with_four_fields x = {1, 2, 3};在4个成员中只有3个被初始化。
09年

在我之前的评论中,第4个成员被初始化为
0。– pmg

5
通常,关于缺少初始化器的警告并不合理。如果您有一个包含4个成员的结构,并且仅为其中3个成员提供了初始化程序,则可能是一个错误。但这{ 0 }是一个通用且定义明确的习惯用法,用于将所有成员初始化为零(为每个子成员递归定义)-这就是为什么修改了gcc的更高版本以不警告该特定情况的原因。
基思·汤普森

@KeithThompson您在说什么?我正在使用gcc 4.8.2,并且自从问题五年过去了。附言:还有一封邮件,我想在最后链接,但令我惊讶的是,它丢失了。邮件服务器可能不会保存所有消息,这很可惜,对于再次遇到问题的人来说,邮件很有用。
Hi-Angel

4
@ Hi-Angel:在Solaris上使用gcc-4.8.1编译一个小程序时,出现“警告:缺少初始化程序”。当我在Linux Mint上使用gcc-4.8.2编译同一程序时,没有收到警告。顺便说一句,您链接到obj = {0};消息中的行不是有效的C,并且gcc 4.8.2拒绝它为语法错误。如果您使用C ++进行编译,请记住这是另一种语言,而gcc使用的前端则不同。gcc的C编译器中的修复程序可能不适用于g ++。
基思·汤普森

Answers:


87

GCC只是过于偏执-我认为没有充分的理由,但是GCC维护人员当然对我所做的C的细微差别了解得更多。

请在GCC邮件列表中查看有关问题的讨论的小话题:

最重要的是-仅仅使用初始化结构{0}实际上将零初始化整个事情。

C99标准在6.7.8 / 21“初始化-语义”中指出以下内容:

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

C90在6.5.7中说的基本上相同,但措辞略有不同(换句话说,C99在这里未添加新内容)。

还要注意,在C ++中对此进行了扩展,因此,空括号“ {}”集将对对象执行值初始化,因为在某些情况下(例如模板),您甚至不知道某个类型的成员或多少个成员可能有。因此,这不仅是一种好习惯,而且有时有必要使初始化列表短于一个对象可能拥有的成员数量。


19
我必须加上-Wno-missing-field-initializers-Wno-missing-braces这样GGC才停止抱怨我= {0};为我的建筑物放东西。有谁知道禁用这些警告是否会错过除= {0};结构以外的其他警告?
马特·克拉克森

4
该修复程序存在于gcc 4.7.0中,但不存在于gcc 4.6.3中
拼接器2012年

1
@splicer:哪个“解决”方法?另外,我也在mingw32-g++.exe (GCC) 4.7.2上面的成语中进行编译并收到此警告(甚至是的确切情况STARTUPINFO)。
Jan Hudec

2
@ Jan Hudec:修订172857。不幸的是,我以前的评论中的URL不再起作用。这是与该修复程序相关的错误:gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
拼接器

9
在我的C ++类中使用空括号{}{0}初始化程序时,即使使用gcc 4.9.3,我仍然会收到警告:/
Kamil Kisiel 2015年

21

通过将结构初始化为C ++程序中的GCC,可以轻松解决此问题

STARTUPINFO startupInfo = STARTUPINFO();
  • 就在几天前

1
这个答案的一个可能的陷阱是,在C ++ 98中,这没有将字段初始化为零。零初始化行为已在C ++ 03中添加。
MM

1
@MM感谢您指出可能的陷阱,但我认为在2018年12月,此代码不应再存在任何危险情况。顺便说一句,我觉得这个答案最好!
彼得·瓦格

@AlBundy不幸的是,仍然有一些编译器使用C ++ 98初始化(例如,我现在恰巧同时打开了C ++ Builder XE5 32位模式)
MM

因此,我必须在文件中添加10多行代码。我真的很生气 试图在函数调用中传递匿名对象。如果我使用{}或{0},则会收到此警告(视为错误)。如果我使用(),则gcc认为这是一个函数调用...
bencemeszaros

15

您使用要求了尽可能多的警告 -Wall -Wextra

在这种情况下,您会收到一条警告,告诉您您未指定所有字段,这是完全有效的,但可能是无意的。

您可以通过添加以下内容来禁止显示此警告: -Wno-missing-field-initializers


12

该网页详细讨论了潜在问题: http //ex-parrot.com/~chris/random/initialise.html

作为一种解决方法,我当前的解决方案是有选择地禁止显示此警告:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
STARTUPINFO startupInfo = {0};
#pragma clang diagnostic pop

可悲的是,这仅适用于clang,似乎不适用于GCC。


4
我可以确认:#pragma GCC diagnostic ignored "-Wmissing-field-initializers"被GCC编译器4.2.1接受,但是什么也不做。不确定gcc的新版本
Maxim Kholyavkin 2014年

1
@speakus,我可以确认它正在使用最新的(在撰写本文时)gcc(7.3.0)。
cydef '18

@cydef根据其他评论以及我所看到的错误报告,GCC不再针对此发出警告(从GCC 5开始)-无论如何#pragma clang diagnostic ignored "-Wmissing-field-initializers"。您可能应该检查是否是这种情况。
WD40

1

在C ++中,您可以boost::initialized_value用来摆脱此警告。我已关闭的警告boost;因此,我不知道这是否会导致您遇到其他任何警告。这样,您不必禁用警告。

例:

T bla = boost::initialized_value;
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.