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
типы возврата были возможны.)