当前位置: 首页 > 知识库问答 >
问题:

当返回对象的函数没有返回语句就结束了,会发生什么

薛俊美
2023-03-14

在 C 中,当一个应该返回对象的函数在没有 return 语句的情况下结束时会发生什么?会得到什么回报?

例如。

std::string func() {}

共有3个答案

夹谷星河
2023-03-14

我很好奇,就在Visual C 2015上做了几个测试。

int f()
{
    if (false)
        return 42;

    // oops
}

int main()
{
    int i = f();
}

我必须添加<code>if</code>以获得警告而不是硬错误:

> cl /nologo /FAs /c a.cpp
a.cpp(6) : warning C4715: 'f': not all control paths return a value

生成的汇编代码非常简单,我删除了不相关的部分。以下是<code>f()的主要内容:

f:
    xor eax, eax
    je label
    mov eax, 42
label:
    ret

xor行基本上是eax=0。因为<code>如果(false)</code>是一个常量条件,生成的代码甚至不需要进行比较,然后将无条件跳转到<code>标签</code>,它只是从函数返回。您可以看到,“返回值”(42)实际上将存储在eax中,但这一行永远不会html" target="_blank">执行。因此,eax==0

以下是<code>main()和<code>所做的:

    call f
    mov _i$[ebp], eax
    ret

它调用<code>f()盲目复制到堆栈上的一个位置(其中<code>i)。因此,i==0

让我们尝试使用对象和构造函数进行更复杂的操作:

struct S { int i=42; };

S f()
{
    if (false)
        return {};

    // oops
}

int main()
{
    S s = f();
}

main()所做的基本上是在堆栈上保留sizeof(S)字节,将第一个字节的地址放在eax中,然后调用f()

    lea eax, _s$[ebp]
    push eax
    call f

同样,f()不会做任何事情,因为它会无条件跳转到函数的末尾:

f:
    xor eax, eax
    je label
    ; some stuff
    ; call S::S(), which would set i to 42
    ; but none of that will happen
label:
    ret

那幺,sizeof(S)字节主要发生了什么?他们从未改变过。它们包含那个特定位置的内存中已经存在的内容。它们含有垃圾。

这是在给定编译器的给定版本上使用未优化的构建。更改编译器,更改行为。启用优化器,彻底改变行为。

别这样。

澹台权
2023-03-14

在 C 中,当一个应该返回对象的函数在没有 return 语句的情况下结束时会发生什么?

它会导致未定义的行为。没人能确切知道会发生什么。

胡承悦
2023-03-14

返回的是什么?

不知道。根据标准,行为是未定义的。

§6.6.3/2 返回语句 [stmt.return]:

(强调地雷)

从构造函数、析构函数或具有 cv void 返回类型的函数的末尾流出等效于没有操作数的返回。否则,流出 main (basic.start.main) 以外的函数的末尾会导致未定义的行为。

事实上,大多数编译器都会给出警告,比如Clang:

警告:控制达到非空隙功能的结束 [-回退型]

 类似资料: