C++ 函数返回字符串
Posted
技术标签:
【中文标题】C++ 函数返回字符串【英文标题】:C++ function returning string 【发布时间】:2018-06-22 08:44:37 【问题描述】:#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;
上面的代码不应该返回任何值并且可能打印垃圾,但它返回“Hey Hello”即使在test函数的末尾没有return语句。 你能告诉我为什么它会这样吗?
【问题讨论】:
由于您的代码有Undefined Behaviour,任何事情都可能发生,包括似乎可以工作。作为一个疯狂的猜测,编译器可能会假设由于test
中的else
分支是非法的,所以if
条件必须始终为真,因此将函数优化为始终return rv;
。
因为UB..
"Hey Hello"
不是有效垃圾吗? ;-)
或者可能只是正确的状态巧合地留在了正确的寄存器中。您希望 rv 被清理和释放,但因为“Hey Hello”是一个 const char 序列,它可能会留在正确的位置。要理解这一点,最好的办法是查看它生成的程序集列表。
C and C++ functions without a return statement的可能重复
【参考方案1】:
在没有任何 return 语句的情况下返回非 void 的函数的末尾是 未定义的行为
如果它们处于活动状态,您应该对这类事情发出编译器警告
允许编译器假设未定义的行为是不可访问的,因此编译器可能已经删除了 if 语句并只保留了不会导致未定义行为的分支
【讨论】:
【参考方案2】:真诚地,我很惊讶这段代码正在编译!您应该将警告视为错误。警告很重要。
我的猜测是编译器作者认为:
每当编码人员有一个没有返回语句的分支时,这可能意味着她知道无法访问该分支(例如,在调用函数之前检查参数的先决条件),因此可以删除该分支。
这可以解释为什么编译器会以这种方式运行。但是对您的问题的更正式的回答是:“这是未定义的行为,一切都可能发生”。
当尝试使用gcc 编译它时,输出取决于优化级别。
【讨论】:
【参考方案3】:首先,您的 test
函数会导致未定义的行为,因为它不会返回,所以实际上任何事情都可能发生。
但是,如果我稍微推测一下,代码的行为可能是这样的,因为它意外地将曾经被 rv
局部变量占用的内存块解释为返回值。而那个对象恰好持有“Hello World”。因此,虽然函数没有正确返回,但堆栈和堆上的内存可以被解释为局部变量就是结果。
尽管如此,这只是一种猜测,根据 C++ 标准,这只是未定义的行为,这意味着您要么知道自己在做什么,并且永远不会让那个不返回的路径执行,要么代码就是错误的。
【讨论】:
【参考方案4】:正如 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
无论 if 语句结果如何,都会到达标签 .LBB0_2,因此在每种情况下都会返回它。
【讨论】:
“意味着一切都会发生” - 也许任何事情都可能发生? @codekaizer 好吧,一切都是任何事物的子集,所以如果有点不精确,这个陈述是正确的。以上是关于C++ 函数返回字符串的主要内容,如果未能解决你的问题,请参考以下文章