【问题标题】:Excess elements in scalar initializer code compiles with gcc but not g++标量初始化程序代码中的多余元素使用 gcc 而不是 g++ 编译
【发布时间】:2014-09-20 04:19:16
【问题描述】:

只是好奇为什么使用 gcc 编译的这段代码(显然是错误的)可以编译,但是使用 g++ 编译的相同代码却没有。

int main()
{
    char *foo = {"bar", "fred", "bob"};

    return 0;
}

gcc 给出了这个警告,但仍然编译并生成二进制文件:

% gcc -o x x.c

x.c:在函数“main”中:x.c:3:5:警告:超出 标量初始化程序中的元素 [默认启用] x.c:3:5: 警告: ('foo' 的初始化附近)[默认启用] x.c:3:5: 警告: 标量初始化程序中的多余元素 [默认启用] x.c:3:5: 警告:(“foo”的接近初始化)[默认启用]

% ls -l x

-rwxr-xr-x 1 overdrive overdrive 6593 Jul 28 21:51 x

g++ 给出了这个错误并且没有任何二进制输出:

% g++ -o y y.cpp

y.cpp:在函数“int main()”中: y.cpp:3:38: 错误:标量对象‘foo’需要初始化器中的一个元素

% ls -l y

ls: 无法访问 y: 没有这样的文件或目录

我使用的 gcc 和 g++ 版本是:

% g++ --version
g++ (Debian 4.7.2-5) 4.7.2 版权所有 (C) 2012 Free Software Foundation, Inc. 这是免费软件;查看复制条件的来源。没有 保修单;甚至不是为了适销性或特定用途的适用性。

有什么好的理由可以在 gcc 中编译而不是在 g++ 中编译吗?或者这显然是一个错误?

【问题讨论】:

  • 编译器当然可以编译无效代码——它是否按预期工作是未定义的
  • 记住:C 和 C++ 是不同的语言。
  • 哪个是最好的g++,它会给你一个错误,或者gcc,它会给你不确定的行为?
  • 你也可以让 gcc 更加严格 (demo)。
  • 好吧,我的问题是如果这是 gcc 编译器的一个错误,因为显然 char* 永远不应该初始化指向 char 的指针数组。

标签: c++ c gcc compiler-errors g++


【解决方案1】:

是的,在 C++ 中让它成为硬错误是有充分理由的,即使在 C 历史上接受的实现上也是如此:

template <typename T, int = sizeof(T{1,2,3,4})>
void f();

template <typename T>
void f(...) { }

int main() { f<int>(); }

这是一个有效的 C++ 程序。编译器不得拒绝此操作,并抱怨不明确的调用或链接器错误,抱怨第一个重载未定义:C++ 标准要求 f&lt;int&gt;() 调用第二个重载,因为第一个重载有替换错误。

考虑到这一点,实现面临两个选择:它们可以始终拒绝多余的初始化器,或者可以仔细确定标准要求在哪些上下文中拒绝它们,以及在哪些上下文中实现可以继续允许它们. GCC 和 clang 开发人员一直选择拒绝它们,这更容易实现。

C 没有任何此类工具可以在编译时确定表达式的有效性,因此对于 C 而言,此类扩展无法导致有效程序被拒绝。

【讨论】:

  • 感谢您回答我的问题。有一个部分我并不真正理解:这部分到底在做什么? int = sizeof(T{1,2,3,4})
  • @BorjaTarraso 它采用表达式T{1,2,3,4} 的大小(从初始化程序{1,2,3,4} 构造一个T 对象),然后继续忽略该大小。所以T{1,2,3,4} 是什么并不重要,它必须是有效的。如果Tint[4],则它是有效的,因为{1,2,3,4} 是一个有效的数组初始化器并且具有正确的长度,但如果Tintint[1],则它是无效的。因为表达式使f 的重载无效,所以f 的另一个重载(对所有类型都有效)成为f&lt;int&gt; 可能引用的唯一函数。
【解决方案2】:

根据 C 2011 标准

标量的初始值设定项应为单个表达式,可选 用大括号括起来

动词应表示编译器应发出诊断消息,:)

所以这是编译器的一个特性或错误。:)

根据 C 标准

1 符合要求的实现应至少产生一个诊断 消息(以实现定义的方式标识)如果 预处理翻译单元或翻译单元包含一个 违反任何语法规则或约束,即使行为是 也明确指定为未定义或实现定义

【讨论】:

  • 不,“shall”并不意味着“shall issue an error”,它根本不是这个意思。所需要的只是诊断。它不必被标记为“错误”,并且一旦发出诊断,该标准对实施没有进一步的要求。 唯一实现不得成功地翻译程序是如果它包含#error指令。
  • Downvote 已删除,尽管我真的不认为这能回答这个问题:它只是表明这两种行为都是有效的,但它没有回答它可能是故意的还是意外的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 2014-07-29
  • 1970-01-01
  • 2012-09-01
相关资源
最近更新 更多