C语言 为什么在递归调用一个行为未定义的函数时不返回垃圾值?

qojgxg4l  于 2023-06-05  发布在  其他
关注(0)|答案(2)|浏览(218)

我在练习基本的C问题时偶然发现了这段代码:

int func(num) {
    if (num > 0) {
        return (num + func(num - 2));
    }
}

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

代码在执行时返回8作为答案。但我认为答案应该是“无法确定”。
我脑海中的递归调用看起来像这样:

5 + func(3)  => 5 + (3 + func(1))
3 + func(1)  => 3 + (1 + func(-1))
1 + func(-1) => 1 + (?)

对于?符号,我认为阅读func(-1)的返回值是未定义的行为。我是基于assumption,对于func(-1),没有显式的int值被返回。因此,在我看来,从表达式(1 + func(-1))中的func(-1)阅读应该会产生一些garbage result + 1
为什么代码返回的答案是8,而不是垃圾?
当我显式地向func传递一个负数并读取结果时,我确实得到了垃圾值,例如下面的代码;

int main() {
    printf("%d\n", (1 + func(-1)));   // returns garbage result and not 0
    return 0;
}

为什么在递归调用中(1 + func(-1))被赋值为0?
我在一台64位机器上用gcc编译代码为gcc myfile.c。编译代码asgcc -W -Wall -ansi -pedantic myfile.c给出了关于func函数的警告,但这不是重点。我不知道8是什么答案。

a11xaf1n

a11xaf1n1#

为什么在递归调用一个行为未定义的函数时不返回垃圾值?
因为“垃圾”并不是你所想的那样。特别是,“垃圾”并不意味着“随机”。(或者如果是这样,它更像是xkcd 221
计算机通常是确定性的。你必须非常努力才能获得真正的随机行为。即使是一个包含最糟糕的未定义行为的程序,每次运行它时,也会经常返回完全相同的奇怪和不确定的数字。
我用了这个类比:
假设你去商店买了一个全新的垃圾桶。但它是完全干净的!一点垃圾都没有!它是如此干净,你可以吃了它!这是虚假广告吗?商店是否欺骗性地卖给你一个非垃圾桶?
查看以上问题的更多讨论:12345。(其中大多数都在谈论未初始化的局部变量的值,而不是未能执行正确的return语句的函数的值,但参数是相同的。

llmtgqce

llmtgqce2#

如果一个C实现遵守C标准的所有适用规则,那么它就符合C标准。
C标准将术语“未定义”定义为“本文档不强加任何要求”(C 2018 3.4.3)。
当一个函数在其关闭}处终止而没有返回值,但程序试图使用返回值时,该行为是未定义的(C 2018 6.9.1 12)。这意味着对行为没有要求。
因此,对于您所展示的代码,没有对行为的要求,因此程序符合C标准的所有规则,无论它输出什么或是否打印任何东西。
特别是,C标准并不禁止程序打印“8”,也不要求程序打印一个奇怪的或大的数字,或者在你看来像“垃圾”的数字。

相关问题