混淆关于return语句的内容

11 浏览
0 Comments

混淆关于return语句的内容

int demo()
{
   static int i = 1;
   return i++;
}
int main()
{
    printf("%d %d %d\n", demo(), demo(), demo());
    return 0;
}  

output:-

3 2 1

在第一次调用demo函数时,返回值为1。我听说当执行return语句时,控制权会传递给调用函数,而不会继续执行被调用函数中的代码。所以我的问题是,在我的代码中,当第一次调用返回1时,为什么它的值会增加?换句话说,我想知道在返回1之后,为什么会执行++操作?

0
0 Comments

关于return语句的困惑和解决方法

在下面的内容中,有人对于return语句的执行顺序产生了疑问,他想知道在返回1之后,为什么还会执行++操作?

这是因为C标准中对后缀递增运算符的定义如下:

6.5.2.4 后缀递增和递减运算符

[...]

2 后缀++运算符的结果是操作数的值。在得到结果之后,操作数的值会自增。(也就是说,相应类型的值1会被加到操作数上)

因此,在执行return语句之前,变量i会被递增,但由于后缀运算的结果是“原始”值,return语句返回的是这个“原始”值。这就是为什么在返回1之后还会执行++操作的原因。

为了解决这个问题,可以使用前缀递增运算符来改变return语句的执行顺序。前缀递增运算符会先使操作数自增,然后返回自增后的值。这样,return语句就可以返回递增后的值了。例如,可以将代码修改为:

return ++i;

这样就可以保证在返回1之前先执行++操作,然后返回递增后的值。这样就解决了关于return语句执行顺序的困惑。

0
0 Comments

关于返回语句的困惑

在理解这个问题之前,有三点需要记住:

  1. static变量在函数中只要被创建一次,就会在整个程序的运行期间持续存在。
  2. 返回的变量还有后缀的++操作符,意思是:“使用这个值(即返回它),然后在之后对它进行递增”:递增后的值不会被返回。

这就是为什么这个变量会记住发生的事情并递增的原因。

为什么你看到的是"3 2 1"而不是"1 2 3"呢?

参数的求值顺序是不确定的,由编译器决定,参考https://stackoverflow.com/a/12960263/1938163

如果你真的想知道这个值是如何先返回再递增的,可以查看生成的汇编代码:

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:                               # 
    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是一个寄存器,一个足够容纳一个值或一个地址的内存位置。它们不是变量,当你设置一个寄存器时,它会一直持续到下一次改变,所以在上面的代码中,它被用来在静态变量之间传递值。

0
0 Comments

混淆有关返回语句的问题是因为代码中使用了静态变量和返回值。解决方法是理解静态变量在整个程序执行过程中的持久性,并正确理解返回语句的执行顺序。

静态变量在函数结束并返回值后仍然保留在堆栈中,这是由于静态变量的特性。因此,在每次调用函数时,静态变量会保留上一次调用结束时的值。对于给定的代码示例,首次调用函数时,静态变量i的初始值为1,然后返回1并将i递增为2。第二次调用函数时,静态变量i的值为2,然后返回2并将i递增为3。第三次调用函数时,静态变量i的值为3,然后返回3并将i递增为4。

因此,最终的输出结果将是1、2、3。

希望这能帮到你!

0