在C语言中如何从函数返回{0}?

15

我在将代码编译为'C'和编译为'C++'时得到了以下差异

struct A {
  int x;
  int y;
};

struct A get() {
  return {0};      
}

在编译为'C++'时一切正常。 但是,在编译为'C'时,我遇到了:

错误:预期表达式

我可以通过执行以下操作来解决:

return (struct A){0};      

然而,我想知道这个差异来自哪里。有人能指出语言参考文献中这个差异是从哪里来的吗?


我认为C++编译器会自动将返回值转换为“struct A”。在C++中,您不需要使用“struct A get()”,只需使用“A get()”。 - Iharob Al Asimi
4
你是否尝试在C++11之前使用C++编译器进行测试?我很确定它也会出问题。(附链接:http://ideone.com/PBFlOR) - WhozCraig
我认为这与C++11引入的自动返回类型推断直接相关。 - Abhishek Gupta
我认为**这个链接**可能会有所帮助。给定链接中的第二段(以“复合字面量用于标量类型”开头)回答了你的问题。 - barak manos
4
你难道不知道C和C++是两种_独立的_语言吗?这就好像你试图将它编译为PHP,然后询问什么机制导致执行失败一样。完全疯狂! - Lightness Races in Orbit
1个回答

24

这两种机制完全不同,其中一种是特定于C++11的,而另一种是特定于C99的。

第一部分,

struct A get() {
  return {0};
}

C++11中取决于[stmt.return] (6.6.3 (2)),该条款规定:

(...) 带有花括号初始化列表的返回语句通过从指定的初始化器列表进行复制列表初始化来初始化要从函数返回的对象或引用。 [ 例如:

std::pair<std::string,int> f(const char *p, int x) {
  return {p,x};
}

这段代码在C(以及C++11之前的C++)中不存在,因此C编译器无法处理它。

另一方面,

-- 结束示例 ]

struct A get() {
  return (struct A){0};
}

使用了C99特性中的“复合字面量”,这在C++中并不存在(尽管一些C++编译器,尤其是gcc,以语言扩展的形式提供此特性;gcc会用-pedantic警告)。该语义在C99标准的第6.5.2.5节中有详细描述;关键引文如下:

 

4、由带括号的类型名后跟花括号括起来的初始化列表组成的后缀表达式是一个复合字面量。它提供了一个未命名对象,其值由初始化列表给出。(脚注80)

 

80)请注意,这与强制转换表达式不同。例如,强制转换仅指定对标量类型或void的转换,强制转换表达式的结果不是左值。

因此,在这种情况下,(struct A){0}是一个未命名的对象,并被复制到返回值中返回。(注意现代编译器将省略此副本,因此您无需担心运行时开销)

所以,这就是所有的信息了。为什么这些特性以各自编程语言中的方式存在可能会成为一场迷人的讨论,但我担心任何外部标准化委员会的人都难以给出权威答案。这两个特性是在C和C++分道扬镳之后引入的,它们并不是并行开发的(也没有意义这样做)。即使是小事,分歧也是不可避免的。


顺便问一下,(struct A){0} 实际上返回的是什么?据我所知,return 语句应该是 (struct A){0, 0} - haccks
1
@hackks:在花括号初始化列表中未提及的内容将被初始化为零(请参见C99中的6.7.8(21))。这也适用于普通结构体和数组初始化。 - Wintermute
@Wintermute; 如果return语句是(struct A){.x = 0},那就是这种情况。而且这个引用与数组初始化有关。我问这个问题是因为我不确定结构体,或者可能是我记忆中遗漏了这一点。 - haccks
好的。在此找到:C99-6.7.8: (p17): 每个括号括起来的初始化列表都有一个关联的当前对象。当没有指定时,按照当前对象的类型顺序初始化当前对象的子对象:数组元素按递增下标顺序,结构体成员按声明顺序,联合体的第一个命名成员 - haccks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接