如果你没有在C++中返回一个值,会发生什么?

Jas*_*ker 14 c++ g++ return-value

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

SomeStruct getSomeStruct()
{
    SomeStruct input;

    cin >> input.x;
    cin >> input.y;
}
Run Code Online (Sandbox Code Playgroud)

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

Gre*_*ill 20

从声明为返回值的函数(不显式返回值)的末尾落下会导致不确定的后果.对于gcc,您应该-Wall从命令行开关开始,该开关打开最有用的警告.控制所需警告的特定gcc警告-Wreturn-type(包括在内-Wall,我只是为了完整性而提到这一点).

一旦打开警告,您还应该-Werror将警告视为错误,并使构建在检测到错误时停止.

  • 我一直很惊讶这只是一个警告而不是错误。它带来的伤害远多于它所带来的帮助。 (2认同)

DGe*_*try 8

大多数现代CPU架构的调用约定指定一个特定的寄存器,以将函数返回值传递回调用者.调用者进行函数调用,然后使用指定的寄存器作为返回值.如果您没有显式返回值,则调用者仍将使用该寄存器中发生的任何垃圾.

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

不幸的是,即使对函数进行微不足道的更改也会导致寄存器分配发生变化,因此返回值将变为真正的垃圾.


Ces*_*arB 7

是否隐式创建并初始化了另一个SomeStruct?

考虑如何返回结构.如果这两个x和y是32位,它是太大,不适合在寄存器中的32位架构,并且同样适用于64位值在64位架构(@Denton金特里的回答提到如何返回简单的值) ,所以必须在某处分配.为此使用堆将是浪费,因此必须在堆栈上分配它.但它不能在getSomeStruct函数的堆栈框架上,因为在函数返回后它不再有效.

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

还有一些优化,例如"命名值返回优化",其中可以省略额外的副本.因此,如果您使用了缺失return,结果将直接在调用者分配的空间上创建,而不是创建临时和复制它.

要了解更多有关正在发生的事情,您必须查看调用者函数.它是否正在初始化(为零)一个"空" SomeStruct,您稍后会为其分配getSomeStruct函数的返回值?或者它正在做其他事情?