只是好奇为什么这个代码(显然是错的)使用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 7月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 ++编译?或者它显然是一个错误?
答案 0 :(得分:8)
是的,有一个很好的理由使它成为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<int>()
调用第二个重载,因为第一个重载有替换错误。
考虑到这一点,实现面临两个选择:它们可以始终拒绝多余的初始化者,或者他们可以仔细确定标准要求拒绝它们的上下文,以及在哪些上下文中实现可以继续允许它们。 GCC和clang开发人员选择不断拒绝它们,这更容易实现。
C在编译时没有任何确定表达式有效性的工具,因此对于C,这种扩展无法使有效程序被拒绝。
答案 1 :(得分:2)
根据C 2011标准
标量的初始化程序应该是单个表达式,可选 括在括号中
动词应表示编译器应发出诊断消息:)
所以它是编译器的一个特性或错误。:)
根据C标准
1符合要求的实施应至少产生一种诊断 消息(以实现定义的方式标识)如果a 预处理翻译单元或翻译单元包含一个 违反任何语法规则或约束,即使行为是 也明确指定为未定义或实现定义的