代码之家  ›  专栏  ›  技术社区  ›  Volkov Sergey

C函数gcd工作正常,但我不明白为什么

c
  •  0
  • Volkov Sergey  · 技术社区  · 1 年前

    我创建了一个函数来计算GCD。它工作正常,但我不明白为什么。它在末尾不返回值。

    计算GCD:

    #include <stdio.h>
    #include <stdlib.h>
    
    int gcd(int a, int b);
    
    int main() {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("GCD = %d.\n", gcd(a, b));
    }
    
    int gcd(int a, int b)
    {
      if (a < b) {
        int tmp = a;
        a = b;
        b = tmp;
      }
      
      int q = a % b;
      if (q == 0)
        return b;
        
      gcd(b, q);
    }
    

    使用不同的值进行调试和测试。函数不应正常工作,因为它在末尾没有返回值。

    1 回复  |  直到 1 年前
        1
  •  4
  •   Eric Postpischil    1 年前

    虽然这种行为不是由C标准定义的,但它是事物工作方式的自然结果。

    函数返回值的规则通常规定,如果类型允许,返回值将存储在指定的处理器寄存器中。什么时候? gcd 递归调用自身,最终其中一个调用满足 q == 0 case然后执行 return b; ,它将值放入指定的寄存器中,然后从函数调用中返回。

    之间的所有来电者 main 最深的 gcd 调用已执行 gcd(b, q); 作为他们最后的声明。所以,在这句话之后,他们什么也不做,只会回到来电者身边。这会将上一次调用的返回值保留在指定的寄存器中。

    最终的效果是 主要的 例程在预期位置接收函数的返回值。

    例如,如果从函数返回值的规则是将其放在调用者堆栈帧中的指定位置,则不会发生这种情况。在这种情况下,最深的调用会将返回值存储在第二深的调用帧中,但该调用不会在其调用者帧中存储任何内容,因此返回值不会在调用链上传播。

    有时编译器优化会破坏未定义的行为。然而,在这种情况下,对于优化或更改使用的编译器,行为可能相当稳定。给定此代码 gcd 例程,编译器很难重新定位 gcd(b,q); 它没有理由在该调用后插入任何可能破坏返回寄存器的代码。