16

我写了一个打印表格的程序。我没有在主函数中包含返回语法,但是每当我输入 echo $? 它显示 12。

我的源代码:

#include <stdio.h>


int main(void)
{
    int ans,i,n;
    printf("enter the no. : ");
    scanf("%d",&n);

    for(i=1;i<=10;i++)
    {
        ans = n*i;
        printf("%d * %d = %d\n",n,i,ans);
    }
}

我没有写return 12,但每次执行程序时它仍然返回12。

谢谢。

4

4 回答 4

20

正如 swegi 所说,这是未定义的行为。 正如 Steve Jessop 等人所说,在 C89 之前它是一个未指定的值,并在 C99 中指定(观察到的行为不符合 C99)

在大多数环境中实际发生的情况是最后一个返回值printf留在用于返回值的寄存器中。

因此,n == 0 时为 11,如果 n 为一位数,则为 12,两位数 n 为 14,三位数 n 为 16,依此类推。

于 2010-09-16T13:26:35.923 回答
19

回答是因为所有现有的答案都说这是未定义的行为,这是不正确的,所以我没有什么可以支持的。

在 C89 中(感谢 pmg 参考标准草案),5.1.2.2.3:

从初始调用返回到主函数等效于以主函数返回的值作为参数调用退出函数。如果到达终止 main 函数的 },返回给宿主环境的终止状态是未指定的。

在 C99 中,引用 n1256, 5.1.2.2.3:

如果 main 函数的返回类型是与 int 兼容的类型,则从初始调用到 main 函数的 return 等价于以 main 函数返回的值作为参数调用 exit 函数;到达终止 main 函数的 } 返回值 0。如果返回类型与 int 不兼容,则返回给宿主环境的终止状态未指定。

因此,这不是“未定义的行为”:它的行为就像main函数返回一样,但在 C89 中,返回的值没有由标准指定。对于您的示例程序,在您的实现中,返回的值似乎始终为 12,这可能是 Ben Voigt 所说的原因。由于您使用的是 linux,因此将代码编译为 C99(或者无论如何,使用 gcc 几乎兼容的 C99 模式编译它)可能并不是什么大的变化。

对于任何返回值的函数,除了 之外main,它未定义的行为,除非调用者不使用返回值(n1256,6.9.1/12):

如果到达终止函数的 },并且调用者使用了函数调用的值,则行为未定义。

我不确定是否main应将最初的呼叫提及为排除在此一般规则之外。不需要是:从标准的POV来看,那个调用没有调用者,所以我认为函数调用的值不是“被调用者使用”,即使它变成了终止状态为程序。

于 2010-09-16T15:22:26.703 回答
1

如果您完全熟悉汇编语言,您可能还记得函数的“返回值”是通过 EAX 寄存器传递的。

在这种情况下,返回值是从 EAX 中读取的。在这种情况下,恰好是 12。

但是,您没有明确设置此值,它只是代码其余部分的产物(或者可能只是偶然)。

正如已经说过的,这绝对是undefined behavior。如果你只是好奇为什么会这样,请考虑这个解释。

但是,在任何情况下都不要试图故意将此值用作任何有意义的东西。

于 2010-09-16T13:25:25.340 回答
0

您的程序在应该返回任何内容时不返回任何内容,从而导致未定义的行为,因此调用者通常会在过程返回时获取 eax 寄存器(在 x86 上,rax 在 x64 上)的值,这通常是垃圾eax 的最后一次使用(通过函数返回值或仅基于寄存器的变量),在这种情况下,它可能是 printf 已写入标准输出缓冲区的 char 的数量

于 2010-09-16T13:30:40.293 回答