当我们在C语言的调用函数中不使用return语句时会发生什么?

时间:2019-04-24 08:21:47

标签: c return-value

我想知道以下程序的输出。主要担心的是,当我们在调用函数中不使用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语句会怎样?

2 个答案:

答案 0 :(得分:5)

请参见the C11 draft standard中的6.9.1(函数定义)/ 12(C99中使用相同的语言):

  
      
  1. 如果到达终止函数的},并且调用者使用了函数调用的值,则行为是不确定的。
  2.   

(在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()返回而未设置返回值时,该语言允许发生任何事情,包括泄露机密。 这就是为什么忘记返回值可能是一个安全漏洞的原因。它可能允许攻击者提取他们不应该知道的信息,或者触发错误的代码执行路径,这些错误在正确的行为中是不可能的,因为函数会“返回”不在预期返回值范围内的值。