Привет мир в APUE Глава 7 выход с кодом 0 - PullRequest
0 голосов
/ 29 сентября 2018

Глава 7 APUE сообщает, что этот фрагмент завершится с кодом выхода, отличным от 0 (например, 13).Но он завершается с кодом 0 на моем компьютере:

#include    <stdio.h>

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

Среда Compile & Running:

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 голосов
/ 29 сентября 2018

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) он может напечатать номер мусора;если бы я допустил межпроцедурную оптимизацию, компилятор мог бы сделать вывод, что единственный способ, которым программа не имеет неопределенного поведения, - это если она никогда не запускается, и, следовательно, выдал никакого кода для него.

(Программа не будет иметь неопределенное поведение, если значение, возвращаемое print_hello, никогда не использовалось. Это еще один особый случай в языке ради обратной совместимости с кодом, написанным ранее void типы возврата были возможны.)

0 голосов
/ 29 сентября 2018

Тур APUE глава неверна.Основная функция в языке Си по стандарту гарантирует возврат нуля, если нет оператора возврата (если мы считаем стандарт не старше 20 лет)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...