【问题标题】:Why is the compiler throwing this warning: "missing initializer"? Isn't the structure initialized?为什么编译器会抛出此警告:“缺少初始化程序”?结构没有初始化吗?
【发布时间】:2010-12-05 01:36:57
【问题描述】:

我正在为一个程序创建某种前端。为了启动程序,我使用了调用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);

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

【问题讨论】:

  • 警告就是:警告。在这个特定的场合可以忽略这个特定的警告。在以下情况下,编译器会发出警告以帮助您:struct struct_with_four_fields x = {1, 2, 3}; 其中只有 4 个成员中的 3 个被初始化。
  • 在我之前的评论中,第 4 个成员被初始化为 0。
  • 警告缺少初始化器通常不是不合理的;如果您有一个包含 4 个成员的结构并且您只为其中的 3 个提供了初始化程序,那么这很可能是一个错误。但是{ 0 } 是一个通用且定义明确的习惯用法,用于将所有成员初始化为零(为每个子成员递归定义)——这就是为什么后来的 gcc 版本已被修改为不对这种特殊情况发出警告。
  • @KeithThompson 你在说什么? I am using gcc 4.8.2,自从这个问题五年过去了。附:还有一封邮件,最后我想链接它,但令我惊讶的是它不见了。可能邮件服务器没有保存所有的邮件,很遗憾,邮件对再次遇到问题的人有用。
  • @Hi-Angel:当我在 Solaris 上使用 gcc-4.8.1 编译一个小程序时,我收到“警告:缺少初始化程序”。当我在 Linux Mint 上使用 gcc-4.8.2 编译相同的程序时,我没有收到警告。顺便说一句,message you linked to 中的行 obj = {0}; 不是有效的 C,gcc 4.8.2 将其作为语法错误拒绝。如果您正在编译为 C++,请记住它是一种不同的语言,并且 gcc 使用不同的前端; gcc 的 C 编译器中的修复可能适用于 g++,也可能不适用于 g++。

标签: c winapi gcc


【解决方案1】:

GCC 只是过于偏执——在我看来没有什么好的理由,但是 GCC 维护者确实比我更了解 C 的细微差别。

在 GCC 邮件列表中查看这个关于该问题的小讨论:

底线 - 仅使用 {0} 初始化结构实际上将零初始化整个事物。

C99 标准在 6.7.8/21 "Initialization - Sematics" 中说明如下:

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

C90 在 6.5.7 中的表述基本相同,但措辞略有不同(换句话说,C99 没有在此处添加新内容)。

另请注意,在 C++ 中,这已被扩展,因此一组空大括号“{}”将对对象执行值初始化,因为在某些情况下(如模板),您甚至不知道成员是什么或者一个类型可能有多少个成员。因此,这不仅是一种好的做法,而且有时还需要一个比对象可能拥有的成员数更短的初​​始化列表。

【讨论】:

  • 我必须添加-Wno-missing-field-initializers-Wno-missing-braces,这样GGC 才不会抱怨我为我的结构添加= {0};。有谁知道禁用这些警告是否会错过除= {0}; 结构之外的其他警告?
  • 修复存在于gcc 4.7.0,但不存在于gcc 4.6.3
  • @splicer:哪个“the”修复?此外,我正在使用mingw32-g++.exe (GCC) 4.7.2 进行编译,并在上面的成语中收到此警告(甚至是STARTUPINFO 的确切情况)。
  • @Jan Hudec:修订版172857。不幸的是,我以前的 cmets 中的 URL 不再有效。这是与修复相关的错误:gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
  • 在我的 C++ 类中使用空括号 {}{0} 初始化程序时,即使使用 gcc 4.9.3,我仍然收到警告:/
【解决方案2】:

这可以通过将结构初始化为 C++ 程序中的 GCC 轻松修复

STARTUPINFO startupInfo = STARTUPINFO();
  • 几天前刚刚这样做

【讨论】:

  • 这个答案的一个可能陷阱是,在 C++98 中,这并没有对字段进行零初始化。在 C++03 中添加了零初始化行为。
  • @M.M 感谢您指出可能的陷阱,但我认为在 2018 年 12 月,代码中不应再出现任何危险情况。顺便说一句,我觉得这个答案最好!
  • @AlBundy 不幸的是,仍然有一些编译器使用 C++98 初始化(例如,我现在巧合地打开了 C++Builder XE5 32 位模式)
  • 因此我不得不在我的文件中添加 10 多行代码。我真的很生气。试图在函数调用中传递匿名对象。如果我使用 {} 或 {0},我会收到此警告(视为错误)。如果我使用 () 那么 gcc 认为这是一个函数调用...
【解决方案3】:

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

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

您可以通过添加 -Wno-missing-field-initializers

【讨论】:

    【解决方案4】:

    此网页详细讨论了根本问题: 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。

    【讨论】:

    • 我可以确认:#pragma GCC diagnostic ignored "-Wmissing-field-initializers" 被 GCC 编译器 4.2.1 接受,但什么也不做。不确定 gcc 的新版本
    • @speakus,我可以确认它正在使用最新的(在编写时)gcc (7.3.0)。
    • @cydef 根据其他 cmets 和我看到的错误报告,GCC 不再警告(从 GCC 5 开始)——不管#pragma clang diagnostic ignored "-Wmissing-field-initializers"。您可能应该检查是否是这种情况。
    【解决方案5】:

    在 C++ 中,您可以使用 boost::initialized_value 来消除此警告。我关闭了boost 的警告;所以我不知道这是否会在您的情况下引起任何其他警告。这样您就不必禁用警告。

    例子:

    T bla = boost::initialized_value;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-30
      • 1970-01-01
      • 2012-07-18
      • 2014-03-06
      • 2023-03-12
      • 2020-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多