C++函数返回字符串

3
#include <iostream>

using namespace std;

string test(string s)
{
    string rv = "Hey Hello";
    if(s=="")
        return rv;
    else
        cout<<"Not returning"<<endl;

}

int main()
{
    string ss = test("test");
    cout<<ss<<endl;
}

上面的代码不应该返回任何值,可能会打印垃圾信息,但即使在test函数末尾没有return语句,它仍然返回“Hey Hello”。 你能告诉我为什么会这样吗?

6
由于您的代码存在“未定义行为”,因此任何事情都可能发生,包括“表现出正常工作”。猜测编译器可能会假设test函数中的else分支是非法的,因此if条件必须始终为真,从而优化函数以始终返回rv - BoBTFish
2
由于未定义行为.. - Jarod42
7
“Hey Hello” 不就是有效的垃圾吗?;-) - Jarod42
1
或者可能恰好正确的状态巧合地留在正确的寄存器中。你期望rv被清理和释放,但因为“Hey Hello”是一个const char序列,它很可能会留在正确的位置。最好的方法是查看生成的汇编清单以了解这一点。 - Rup
3
可能是C和C ++函数没有返回语句的重复问题。 - xskxzr
显示剩余2条评论
4个回答

6

如果一个非void返回类型的函数没有任何返回语句就结束了,这是未定义行为。

如果编译器警告处于激活状态,你应该会收到此类警告。

编译器可以假定未定义行为是不可达的,因此编译器可能已经删除了if语句,并只保留了不会导致未定义行为的分支。


1

我很惊讶这段代码竟然编译成功了!你应该把警告视为错误,警告很重要。

我的猜测是编译器的作者认为:

如果程序员有一个没有返回语句的分支,那么她可能知道这个分支不会被执行(例如,在调用函数之前检查参数的先决条件),因此可以删除该分支。

这可能解释了编译器的行为。但对于你的问题,更正式的答案是:“这是未定义的行为,一切皆有可能”。

尝试使用gcc编译时,输出结果取决于优化级别。


0
正如Tyker所提到的,这段代码会导致未定义的行为,意味着任何事情都可能发生。
最有可能是由优化器引起的,它假设每个执行分支都返回某个值,并基于此优化最终代码。您应该尝试关闭优化,但请注意,每个编译器都可以生成完全不同的结果。
看一下这个函数的反汇编(clang 4.0,-O3)(我使用char*代替std::string):
test: # @test
  mov eax, .L.str.1
  cmp rdi, rax
  je .LBB0_2 // <<-- IF .L.str.1 == "", goto .LBB0_2
  // CALL PRINTF
  push rax
  mov edi, .L.str.2
  xor eax, eax
  call printf
  add rsp, 8
  // END OF CALL PRINTF
  .LBB0_2:
  mov eax, .L.str // <<--- RETURN .L.str to the caller (optimization!)
  ret

.L.str:
  .asciz "Hey Hello"

.L.str.1:
  .zero 1

无论条件语句的结果如何,标签.LBB0_2都会被执行,因此它在每种情况下都会被返回。


“meaning everything can happen” - 可能是 任何事情都可能发生 - Joseph D.
@codekaizer 嗯,一切都是任何事物的子集,所以这个陈述是正确的,尽管有点不够精确。 - eerorika

0
首先,你的 `test` 函数导致未定义行为,因为它没有返回值,所以可能发生任何事情。
然而,如果我要猜测一下,代码的行为可能是因为它无意中将曾经被 `rv` 局部变量占用的内存块误解为返回值。而且那个对象恰好保存着 "Hello World"。所以尽管函数没有正确返回,但堆栈和堆上的内存可以被解释为局部变量就是结果。
尽管如此,这只是一个猜测,根据 C++ 标准来说,这只是未定义行为,这意味着要么你知道自己在做什么,从不让这种不返回的路径执行,要么代码就是错误的。

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