我想知道以下程序的输出。主要担心的是,当我们在调用函数中不使用return语句时会发生什么?
int sum(int x, int y)
{
//return x+y;
}
int main()
{
int res=0;
res=sum(1,2);
printf("res = %d\n",res);
}
如果我使用sum()
,请在上述功能return x+y
中;它将输出3作为输出?
如果我不使用return语句会怎样?
答案 0 :(得分:5)
请参见the C11 draft standard中的6.9.1(函数定义)/ 12(C99中使用相同的语言):
- 如果到达终止函数的
}
,并且调用者使用了函数调用的值,则行为是不确定的。
(在C90中,6.6.6.4(return
语句中大部分是等效语言):
如果执行了不带表达式的
return
语句,并且调用者使用了函数调用的值,则该行为未定义。到达终止函数的}
等同于执行不带表达式的return
语句。
区别是(从C99开始)在非void函数中具有return;
并且没有表达式的错误。)
在您的情况下,到达}
的{{1}}(未执行sum
语句)并使用了返回值:
return
因此,您的代码具有未定义的行为:可能发生任何事情,从res=sum(1,2);
中的垃圾值到无限循环或崩溃。
答案 1 :(得分:0)
melpomene's answer是100%正确的:从没有返回值的非void函数返回总是导致未定义的行为。在那之后,所有的赌注都关闭了。
我要补充一点,可能会发生什么:
当您调用函数时,编译器会遵循一组规则,这些规则涉及如何将参数和返回值传递给被调用方。这些规则遵循“如果第一个参数是整数类型,则在调用被调用者之前将其放入寄存器eax
”中。因此,如果您说foo(42)
,则编译器发出代码以将42
加载到寄存器eax
中,然后调用foo
,然后该代码仅检查在其中找到的值注册eax
知道通过了什么。
返回值也是如此。在一个明确的位置,调用者可以期望返回值(这可以是寄存器或堆栈上的内存位置),而被调用者有义务在其中实际放置一个有意义的值。
因此,当您忘记命名返回值时,将不会设置返回值。调用者将解释为各自寄存器/存储器位置中的任何内容。究竟有效地“传回”给调用者的确切内容取决于100%被调用者恰好被编译,并且可能是确定性的。考虑以下代码片段:
int getSecret() {
return 42;
}
int checkSecret(int guess) {
int secret = getSecret();
//return secret == guess;
}
int main() {
printf("The secret is %d.\n", checkSecret(0));
}
如果编译并运行此代码,则可能会发现它可以正确打印秘密值42
。为什么?简单:当getSecret()
返回秘密值时,它将放置在checkSecret()
期望找到该返回值的位置。而且这可能与main()
期望找到checkSecret()
的返回值的寄存器相同。
从语言的角度来看,这是完全可以的:当checkSecret()
返回而未设置返回值时,该语言允许发生任何事情,包括泄露机密。 这就是为什么忘记返回值可能是一个安全漏洞的原因。它可能允许攻击者提取他们不应该知道的信息,或者触发错误的代码执行路径,这些错误在正确的行为中是不可能的,因为函数会“返回”不在预期返回值范围内的值。