【问题标题】:confusion regarding return statement [duplicate]关于退货声明的混淆[重复]
【发布时间】:2014-03-15 13:57:03
【问题描述】:
int demo()
{
   static int i = 1;
   return i++;
}

int main()
{
    printf("%d %d %d\n", demo(), demo(), demo());
    return 0;
}  

输出:-

3 2 1

在第一次demo 调用期间,返回1

我听说,当return 语句被执行时,控制权就会传递给calling 函数,而无需进一步执行called 函数中的代码。

所以我的问题是,在我的代码中,当1 在第一次调用中返回时,为什么它的值会增加?

也就是说我想知道返回1之后,为什么会执行++

【问题讨论】:

  • postfix ++ 返回旧的递增变量。不要混淆这两个概念。增量是运算符的副作用。
  • 在编译这个程序时使用 gcc 的-Wall 选项,它会警告你行为可能未定义!
  • 很像 this question 不久前问的。
  • @Elazar :但在我的情况下,当返回值时,它是如何递增的,因为控件现在位于 main()
  • @JoachimPileborg 它的实现已定义。

标签: c return


【解决方案1】:

这里要记住三点:

  1. static 函数中的变量在第一次创建后会在程序的整个持续时间内持续存在

  2. 返回的变量也有 后缀 ++ 运算符,意思是:“使用该值(即返回它)并在之后增加它”:不返回增加的值。

这就是为什么该变量对所发生的事情具有“记忆”并不断增加的原因。

-> 为什么你看到的是“3 2 1”而不是“1 2 3”?

评估参数的顺序“先验”未知,由编译器决定,请参阅https://stackoverflow.com/a/12960263/1938163


如果您真的想知道值是如何先返回然后递增的,请查看生成的 asm 代码:​​

demo():                     # @demo()
    movl    demo()::i, %eax # move i and put it into eax
    movl    %eax, %ecx      # Move eax into ecx -> eax will be used/returned!
    addl    $1, %ecx        # Increment ecx
    movl    %ecx, demo()::i # save ecx into i -> this is for the next round!
    ret                     # returns!

main:                               # @main
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp
    movl    $0, -4(%rbp)
    callq   demo()                  # Call demo()
    movl    %eax, -8(%rbp)          # save eax in rbp-8 (contains 1, demo::i is 2 for the next round)
    callq   demo()                  # Call demo()
    movl    %eax, -12(%rbp)         # save eax in rbp-12 (contains 2, demo::i is 3 for the next round)
    callq   demo()                  # Call demo()
    leaq    .L.str, %rdi            # load str address
    movl    -8(%rbp), %esi          # esi points to 1
    movl    -12(%rbp), %edx         # edx points to 2
    movl    %eax, %ecx              # move eax (3) into ecx (demo::i is 4 but doesn't get used)
    movb    $0, %al                 # needed by the ABI to call printf
    callq   printf                  # call printf() and display 3 2 1
    movl    $0, %ecx
    movl    %eax, -16(%rbp)         
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    ret

demo()::i:

.L.str:
    .asciz   "%d %d %d\n"

64 位 ABI 使用寄存器(RDI、RSI、RDX、RCX、R8 和 R9)而不是堆栈来传递参数。

【讨论】:

  • 请告诉我eax 是什么意思?
  • eax 是一个寄存器,一个小到足以包含值或地址的内存位置。它们不是变量,当您设置一个时,它会一直存在,直到您再次更改它,因此在上面它用于移动静态变量值。
【解决方案2】:

您的函数返回 i 的旧值并将其递增。由于您使用了static 关键字,i 的值被存储并可供下次调用(调用后它不会消失)。

我听说,当return 语句被执行时,控制权就会传递给调用函数,而不会进一步执行被调用函数中的代码。

你没听错。但这并不意味着return 语句返回的语句没有执行。看一个例子:

return a + b;  

现在执行此语句,然后首先评估a+b,然后将其值返回给调用者。以类似的方式,当

return i++;

被执行然后i++被执行。它返回 i 的前一个值并将其递增 1

【讨论】:

    【解决方案3】:
    int demo()
    {
       static int i = 1;
       return i++;
    }
    
    int main()
    {
        printf("%d %d %d\n", demo1(), demo2(), demo3());
        return 0;
    }  
    

    demo_i() 的执行顺序取决于语言。

    现在,使用 static 关键字。 Static variables 在程序的整个持续时间内一直保持在 stack 上,即使在 function 结束并且 returns 值之后。

    Due to this , 1st time : i=1  
    return 1 , increment to 2 .  
    2nd time : i=2  
    return 2 , increment to 3 .  
    3rd time : i=3  
    return 3 , increment to 4 .  
    

    希望这会有所帮助!

    【讨论】:

      【解决方案4】:

      [...] 我想知道返回1后为什么会执行++?

      后缀运算符由 C 标准定义,其工作方式如下:

      6.5.2.4 后缀递增和递减运算符

      [...]

      2 后缀 ++ 运算符的结果是操作数的值。结果出来后 获得,则操作数的值递增。 (即适当的值 1 类型被添加到它。)

      所以在return执行之前i是递增的,但是由于后缀操作的结果是“原始”值,return返回这个“原始”值。

      【讨论】:

        猜你喜欢
        • 2023-03-12
        • 2017-10-28
        • 2016-06-23
        • 2012-01-02
        • 1970-01-01
        • 2012-08-12
        • 1970-01-01
        • 2022-01-13
        • 2011-08-10
        相关资源
        最近更新 更多