【问题标题】:How does the return statement work in C?return 语句在 C 中是如何工作的?
【发布时间】:2015-10-06 14:06:44
【问题描述】:

我对 C 中的 return 语句有疑问,它从哪里真正返回:

int base(int a)
{
   if(a == 1)
     return 0;
}

int inherit()
{
   base(1);
   // the rest of the code
}

所以在inherit()函数内部,base()被调用,它执行return 0,在这种情况下; inherit() 中的其余代码仍然执行吗? return 语句究竟是如何工作的?

【问题讨论】:

  • inherit 呼叫base。基返回一个值,您可以在inherit 中使用int ret = base(1); 之类的东西来捕获它。但事实并非如此。它调用base(1) 而不捕获返回值。所以返回值被忽略了。
  • 请注意base() 不会总是返回一个值,用a != 1 调用它会调用未定义的行为
  • 优化编译器根本不会产生任何代码 ;-)。
  • @PeterSchneider:这并不完全准确。由于这两个函数都是外部可见的,因此编译器有义务生成代码,以便可以从其他源文件调用这些函数。但是,它可能会使inherit() 变成一个空函数,因为它可以看到调用base() 没有任何用处(并且inherit() 中没有显示任何其他内容,尽管注释表明那里还有其他代码。
  • @JonathanLeffler 没错,“根本”说得太多了。

标签: c return


【解决方案1】:

您的代码太小了,不舒适。我会觉得更快乐:

int base(int a)
{
    if (a == 1)
        return 0;
    return 37;
}

int inherit(void)
{
    int n = base(1);
    printf("Base(1) is %d\n", n);
    return n + 3;
}

inherit()调用base()时,它的当前状态被存储,函数base()被运行,它返回一个值。在此代码中,返回值被捕获在变量n 中,然后在printf() 调用和inherit() 中的return 中使用。这就是return 的工作原理:它单方面停止当前函数的执行,并在调用函数中继续执行。

即使在main() 中,return 也会终止当前函数并向调用函数返回一个值,即 C 运行时——C 运行时确保进程退出,通常将返回的值传递给 ' environment'(例如 Unix 上的 shell 程序)。

请注意,修改后的代码确保base() 始终返回一个值。不这样做通常会导致未定义的行为。如果该函数仅使用值1 作为参数调用,那将是“OK”,但是你为什么要首先调用该函数。因此,始终确保如果一个函数应该返回一个值,则该函数的所有返回(尤其包括函数末尾的那个)都返回一个值。在原始代码中,最后没有return——这很糟糕!

【讨论】:

  • 嗯,这句话“这就是 return 的工作原理:它单方面停止当前函数的执行,并在调用函数中继续执行[正确到这里,p.s.],直到被调用的函数返回 [它刚刚做到了! ?],然后在调用函数中恢复执行。”有点模糊。被调用函数在return 上返回,然后调用ing 函数照常继续。
  • @PeterSchneider:谢谢。我同意。我已经删除了句子的第二个结尾。
  • 我想知道这里的礼仪:可以马上编辑吗?你介意,有人介意吗? (我不会。)在这种情况下,很可能只是一个编辑错误(我认为您将关于调用的句子与关于返回的句子混为一谈)。
  • @PeterSchneider:是的,可以进行编辑。我会收到通知说您进行了编辑,并且会检查它,但至少会在精神上表示感谢(您会接受这些吗?)。
【解决方案2】:

如果您在代码中调用return,则该函数中的代码将在到达该点后停止工作。然后控制将移回调用它的函数,或者程序将结束,具体取决于程序中返回的位置。

【讨论】:

    【解决方案3】:

    所以在inherit()函数中调用了base(),它返回0,在这种情况下,inherit()中的其余代码还执行吗?

    是的,它会执行。函数base 中的return 将控制权(或值)交还给调用函数。

    然后调用函数inherit() 的其余部分将被执行,直到其作用域结束或在inherit() 中遇到return

    注意 - 如果不满足 if 条件,函数 base 也应该是 return 值。正如其他人指出的那样,如果不是,它将调用未定义的行为。

    【讨论】:

      【解决方案4】:

      如果你写

      int inherit()
      {
        int x=99;
      
        x=base(1);
      
        dothis();
        // the rest of the code
      }
      

      那么 x 现在为 0,程序进入下一行 dothis();

      【讨论】:

        【解决方案5】:

        当然它会继续执行其余的代码。 base 方法仅返回其中的显式 return。这也适用于 inherit 方法。

        如果您希望 inherit 方法返回 base 的值,请添加 return 关键字。

        int inherit()
        {
           return base(1);
           // the rest of the code can now be left out actually
        }
        

        挑剔: 在您的示例中,编译器可能会抱怨,因为在a != 1 的情况下没有返回值。 所以你必须添加类似的东西

        int base(int a)
        {
           if(a == 1)
             return 0;
           else
             return 1;
        }
        

        【讨论】:

        • 我认为 OP 对 inherit() 方法是否也返回更感兴趣 ;-)。
        【解决方案6】:

        return 语句的行为由 ISO C 标准定义。引用N1570 草案,第 6.8.6.4 节:

        return 语句终止当前函数的执行,并且 将控制权返回给它的调用者。一个函数可以有任意数量的 return 声明。

        如果执行带有表达式的 return 语句,则 表达式作为函数调用的值返回给调用者 表达。如果表达式的类型与返回值不同 它出现的函数的类型,值被转换为 通过分配给具有函数返回类型的对象。

        所以如果你有这样的功能:

        int func(void) {
            return 42;
        }
        

        然后你从其他函数调用它(或者甚至从同一个函数;参见 recursion):

        #include <stdio.h>
        int main(void) {
            int result = func();
            printf("%d\n", result);
        }
        

        那么函数调用func() 是一个表达式,它产生值42

        返回类型为void 的函数不返回值。此类函数中的 return 语句只是 return; 没有表达式。它终止函数的执行,但没有返回值。

        【讨论】:

          【解决方案7】:

          由于您没有返回base 的结果,所以inherit 没有理由不执行其余的行。

          函数继续执行直到到达return 语句。在inherit 中,它遇到了一个函数调用-base。调用返回值的函数并不意味着返回该结果。

          例如,如果有人派我去商店取一张收据——那家商店给了我一张收据并不意味着我一定要把它交给最初派我来的人。

          另一方面,这将返回 base 的结果,并且不会执行其余代码。

          int inherit()
          {
             return base(1);
             // the rest of the code
          }
          

          【讨论】:

          • 发布的代码可能会调用未定义的行为
          • @iharob 可能,但我猜 OP 想要更多关于 return 语句的概念性答案,而不是具体的代码审查。
          【解决方案8】:

          return 语句返回调用者可以使用的值。返回值不会影响调用者代码中的任何内容,除了调用者使用该值时(例如检查if 语句中的值)。一旦return被执行,被调用的函数就停止执行,所有的局部变量都被释放了。

          return 语句可以返回单个字大小的值,例如 int 或指针。在较新的 C 版本中,return 语句可以返回复合值(例如结构);在这种情况下,编译器会立即执行复制操作,因为返回的结构可能是被调用函数的本地(自动)变量。由于这些变量是在堆栈上分配的,它们将在调用者的下一次调用中被销毁(覆盖);因此,编译器必须立即保存它们。请注意,返回指向被调用函数的本地(自动)变量的指针是错误的,因为该变量将在返回时被释放并可能被覆盖。

          通常返回的值在寄存器中返回。传统上,在 Intel 中,这是 eax 寄存器。

          例子:

           return i;    // return the value of an int.
           return p;    // return a pointer p
          
           struct MY_STRUCT S= {0};   // local struct S is on the stack
           return S;                  // return the whole structure
           //caller:
           struct MY_STRUCT S2= myFunction(); // compiler copies S to S2
          
          struct MY_STRUCT S= {0};    // local struct S is on the stack
          return &S;                  // return pointer to S !!error:
          //caller:
          struct MY_STRUCT *S= myFunction();  // S will be overwritten with nex call!!
          

          【讨论】:

            【解决方案9】:

            是的,在调用base() 之后,代码将继续运行,但使用 undefined behavior。下面的编辑说明了捕获返回值并在分支语句中使用它。您应该始终包含一个非 void 函数的 return 语句:

            int base(int a)
            {
               if(a == 1)
                 return 0;
               else return -1;//function is provided alternative return path
            }
            
            int inherit()
            {
               int status = base(1);
               if(status == 0)
               {
                  // the rest of the code
               }
               return status;
            }
            

            【讨论】:

            • 如果a != 1,仍然是未定义的行为
            • base() 应该总是返回一些东西
            • @Bathsheba 已编辑。谢谢。
            【解决方案10】:

            C 是面向过程的编程语言,与 OOP 不同的是,C 是面向过程的编程语言 is on is on is on variable, Data Structures & Subroutines.(不过这里的 OOP 也以同样的方式工作)

            当你的程序正在执行时

            int继承()函数

            它会调用

            int base(int a)

            为 a 提供值 1。这是一个子程序。因为,子程序本质上是一组由程序员出于各种原因分组的计算指令,这些原因可能是易于编码或更好的组织等。

            base(1); 子例程完成执行后,加载/执行的下一条指令是紧随其后的指令。

            现在你需要知道你的 inherit() 函数会一直执行,直到它遇到一个指示它停止的代码。其中最常见的是

            exit(0);//exit entire program
            return val;//where val stores an integer(control returns to calling function,or program exits if it the only function
            

            在函数/例程中执行上述代码后,同一函数中的所有代码都不会执行)

            您甚至可以通过键入以下内容从 void 函数返回:

            return;
            

            【讨论】:

              【解决方案11】:

              不考虑遗漏返回值的明显错误:

              int inherit(){
               int return_value =  base(1);
               // ------^
               // the rest of the code
              }
              

              return 语句是如何工作的?

              对于函数调用(在您的情况下,inherit() 调用 base())我们需要返回到函数调用之后的指令,以便程序继续执行循环。此返回需要两条信息:

              1.return 语句表示函数执行结束,在低级和高级语言上具有相同的语义。1

              2.返回地址:处理器如何知道函数调用完成后返回到哪里?这条信息通常在调用函数时存储。因此,当调用一个函数时,除其他外2,返回地址被存储。主要使用两个特殊的地方:特殊寄存器或堆栈。因此,当到达return 语句时,控制流被转移到函数调用3之后的指令地址。

              除此之外,您还可以返回特定值,例如计算的结果等,作为函数签名中预定义的返回类型,其值对是否继续执行没有直接影响。在您的情况下,如果您从函数 base() 返回任何其他类型为 int 的有效值,它将对其余执行产生未定义的含义,因为 base() 没有为所有可能的输入提供返回语句,这将导致未定义的行为

              inherit() 中的其余代码仍然执行吗?

              对于您调用它的值,即:1,它会在base() 函数返回其值后继续执行inherit() 中的任何内容。


              1.高级语言允许默认的贯穿机制。也就是说,如果我们没有显式指定过程的结束,则在块结束时返回控制。

              2。修改 PC(程序计数器)。

              3。实际存储的返回地址取决于处理器。一些 SPARC 等处理器存储调用指令本身的地址。其他 如 MIPS 和 Pentium 存储调用后指令的地址 说明。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-03-21
                • 1970-01-01
                • 2021-10-31
                • 2020-07-09
                相关资源
                最近更新 更多