C++ 如果你不';t返回C+中的值+;?

C++ 如果你不';t返回C+中的值+;?,c++,g++,return-value,C++,G++,Return Value,昨天,我发现自己在写这样的代码: SomeStruct getSomeStruct() { SomeStruct input; cin >> input.x; cin >> input.y; } 当然忘了实际返回我刚刚创建的结构。奇怪的是,这个函数返回的struct中的值被初始化为零(当使用g++编译时)。这仅仅是巧合还是另一个SomeStruct被隐式地创建和初始化了?对我来说,编译器不允许这样做:从声明返回值(而不显式返回值)的函数末尾脱落

昨天,我发现自己在写这样的代码:

SomeStruct getSomeStruct()
{
    SomeStruct input;

    cin >> input.x;
    cin >> input.y;
}

当然忘了实际返回我刚刚创建的结构。奇怪的是,这个函数返回的struct中的值被初始化为零(当使用g++编译时)。这仅仅是巧合还是另一个SomeStruct被隐式地创建和初始化了?

对我来说,编译器不允许这样做:

从声明返回值(而不显式返回值)的函数末尾脱落会导致未定义的后果。对于gcc,应该从打开最有用警告的
-Wall
命令行开关开始。控制所需警告的特定gcc警告是
-Wreturn type
(它包含在
-Wall
中,我只是为了完整起见才提到它)


打开警告后,还应使用
-Werror
将警告视为错误,并使生成在检测到错误时停止。

大多数现代CPU体系结构的调用约定指定一个特定寄存器,以将函数返回值传递回调用方。调用者进行函数调用,然后使用指定的寄存器作为返回值。如果不显式返回值,调用方仍将使用该寄存器中的任何垃圾

编译器还将使用其可用于函数内部计算的所有寄存器。指定用于保存返回值的寄存器也将用于函数内的杂项计算。因此,当您忘记指定返回值时,发现正确的值奇迹般地返回给调用者并不罕见:编译器使用该寄存器存储您的对象

不幸的是,即使是对函数的微小更改也会导致寄存器分配发生更改,因此返回值会变成真正的垃圾

是否在某处隐式创建并初始化了另一个SomeStruct

考虑如何返回结构。如果
x
y
都是32位,那么它太大,无法装入32位体系结构上的寄存器,同样的情况也适用于64位体系结构上的64位值(@Denton Gentry的回答提到如何返回更简单的值),因此必须将其分配到某个位置。为此使用堆是浪费的,因此必须在堆栈上分配堆。但是它不能在
getSomeStruct
函数的堆栈框架上,因为在函数返回后,它不再有效

相反,编译器让调用方通过向被调用函数传递一个指向分配给它的空间的隐藏指针来告诉被调用函数将结果放在何处(可能在调用方堆栈的某个位置)。因此,将其设置为零的位置在调用方,而不是
getSomeStruct
函数上

还有一些优化,如“命名值返回优化”,可以省略额外的副本。因此,如果使用缺少的
返回
,结果将直接在调用者分配的空间上创建,而不是创建临时文件并复制它


要了解更多正在发生的事情,您必须查看调用者函数。它是否正在初始化(归零)一个“空的”
SomeStruct
,您稍后将
getSomeStruct
函数的返回值分配给它?还是它在做其他事情?

您没有收到任何警告,因为您没有打开
-Wall-Werror
。(如其他答覆所述)


然而,我认为您可能得到了一个零填充结构作为结果,因为堆栈对象是在调用函数中默认构造的,可能有显式的零参数,或者由于堆栈上的零?

我觉得这很有趣。使用默认选项时,以下编译器在编译
GetSomeStruct()
函数时具有以下行为:

  • Microsoft VC,所有版本(从VC6开始):

    错误C4716:“getSomeStruct”:必须返回一个值

  • 数字火星:

    警告18:关闭'}'时隐含返回的getSomeStruct不返回值

  • 科莫:

    警告:在非无效函数“getSomeStruct”的末尾缺少return语句

  • 通用条款:

    无错误或警告

给出标准中的以下两句话(6.6.3第2段):

一个不带空格的返回语句 表达式只能在中使用 不返回值的函数, 也就是说,一个返回 键入void、构造函数(12.1)或 析构函数(12.4)。。。流出 函数的结尾等价于 没有价值的回报;这一结果 在未定义的行为中 值返回函数


我想说,在这种情况下,编译器没有理由不给出错误。为什么这么多编译器只给出警告或根本不提供诊断?

看起来它不允许这样做,因为您已将编译器设置为将警告视为错误。你认为这可能是我把某个地方的警告级别设置得太低的情况吗?我一直很惊讶这仅仅是一个警告而不是一个错误。伤害远大于帮助。在C中不返回任何内容是合法的。它仍然没有定义,但至少是合法的。特别是,如果我忘记返回
std::vector
或其他管理堆内存的对象,该对象将处于无效状态,因此当时间到来时,它将不知道如何销毁自己。这使得调试过程变得困难。我反对GCC没有就此发出警告的断言。请使用
-Wall
选项运行gcc,您将得到:
警告:无返回