APUE第7章中的hello world退出,代码为0

时间:2018-09-29 14:07:35

标签: c++ c macos unix

APUE第7章说,该代码段将以非0的退出代码退出(例如13)。但它在我的计算机上以代码0退出:

#include    <stdio.h>

main()
{
    printf("hello, world\n");
}

编译和运行环境:

Darwin cuixiaochens-MacBook-Pro.local 17.4.0 Darwin Kernel Version 17.4.0: Sun Dec 17 09:19:54 PST 2017; root:xnu-4570.41.2~1/RELEASE_X86_64 x86_64

Gcc版本:

♪ apue.3e git:(master) gcc -v Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 Apple LLVM version 9.0.0 (clang-900.0.39.2) Target: x86_64-apple-darwin17.4.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin

2 个答案:

答案 0 :(得分:3)

APUE试图说明一个真实的现象,但仍然可以使用经过修改的程序来观察该现象。

通常,当声明要返回值的函数(即void以外的返回类型)通过“下降”返回时,其返回值是“不确定”,并且观察该值的程序具有“未定义的行为。”表现该未定义行为的一种常见方式是使函数的返回值等于函数内最后一次调用的返回值,因为该值仍在返回值寄存器中。 APUE试图通过掉落main的末尾来证明这一点,但是由于C99出现了掉落main末尾的特殊规则,该规则说这就像main已经正确返回了0。许多编译器甚至在C89模式下也应用了此规则,因为在C89中它是未定义的,因此允许他们执行自己喜欢的任何事情。

因此,要观察APUE希望您观察到的现象,您需要使用main以外的功能,并且还需要采取步骤防止过程间分析,例如将程序分为两个翻译单元然后不使用链接时优化。

/* file1.c */
#include <stdio.h>

int print_hello(void)
{
    printf("hello world\n");
}

/* file2.c */
#include <stdio.h>
extern int print_hello(void);

int main(void);
{
    int n = print_hello();
    printf("print_hello returned %d\n", n);
    return 0;
}

分别编译每个文件,例如cc -c,然后将它们链接在一起作为第三项操作。在我的计算机上,使用我的编译器,将打印出

hello world
print_hello returned 12

请记住,该程序确实具有未定义的行为。在具有不同调用约定的计算机上(例如SPARC),它可能会显示垃圾号码;如果我允许进行过程间优化,则编译器可能推断出程序不具有未定义行为的唯一方法是它永远不会运行,因此为此根本不发出任何代码。 / p>

(如果从未使用print_hello返回的值,程序将不会有未定义的行为。这是该语言的另一种特殊情况,是为了向后兼容所编写的代码在void返回类型之前是可能的。)

答案 1 :(得分:1)

您的APUE章节有误。如果没有返回语句(如果我们认为标准不超过20年),则标准会保证C语言的主要功能返回零。