Ответ 1
Заключение
Причина, по которой GCC дает разные/лучшие сообщения, если указан полный путь заголовка, заключается в том, что препроцессор GCC предоставляет компилятору GCC cc1
информацию о том, что включенный заголовок является системным заголовочным файлом или локальным заголовочным файлом на некоторые цифры в конец строки комментария созданного препроцессором файла .i
.
Затем компилятор cc1
будет генерировать более полезные сообщения, если заголовочный файл является локальным файлом заголовка и будет подавлять сообщение об ошибке, если заголовочный файл является системным заголовком, в соответствии с Документация GCC.
Чтобы нормальная версия кода выводила сообщения об ошибках точно так же, как и код, который указывал полный путь к файлу заголовка, GCC должен прекратить включать все системные каталоги, указав опцию -nostdinc
, а затем явно указывать GCC каталоги, в которых он мог бы искать файлы заголовков, а не обрабатывать каталог как системный каталог, используя флаг -I
.
Для вашего кода командная строка может быть как ниже (GCC_INCLUDE_DIR
является вашим каталогом GCC по умолчанию, для GCC по умолчанию для системы, это может быть /usr/lib/gcc/x86_64-unknown-linux-gnu/4.9.2/include/
):
gcc -c t.c -nostdinc -I/usr/include/ -IGCC_INCLUDE_DIR
Исходный код
Переместил исходный код здесь из этого оригинального сообщения, чтобы сделать этот ответ более полезным.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <term.h>
//#include "/usr/include/term.h"
void clear_screen(void) {
if (!cur_term) {
int result;
setupterm( NULL, STDOUT_FILENO, &result );
if (result <= 0)
return;
}
putp( tigetstr( "clear" ) );
}
int main(void) {
puts("I am going to clear the screen");
sleep(1);
clear_screen();
puts("Screen Cleared");
sleep(1);
clear_screen();
return 0;
}
Разница между созданными препроцессором файлами
Вы можете использовать следующую командную строку, чтобы попросить GCC вывести код, созданный препроцессором. Этот код будет передан в фактический компилятор GCC, cc1
. Если файлы с препроцессором сгенерированы точно так же, поведение компилятора cc1
должно быть точно таким же. (Предположим, что код помещен в файл t.c
)
gcc -E t.c -o t.i
Ниже приведена разница между двумя gcc-препроцессором, сгенерированными файлами .i
. t.fullpath.i
- это файл, сгенерированный с полным файлом заголовка пути, а t.i
- это код без полного пути (некоторые из вывода diff
были удалены, поскольку они являются только различиями в имени файла.)
$ diff t.i t.fullpath.i
2920,2922c2920,2924
< # 1 "/usr/include/term.h" 1 3 4
< # 47 "/usr/include/term.h" 3 4
---
> # 1 "/usr/include/term.h" 1
> # 47 "/usr/include/term.h"
2924,2925c2926,2927
< # 48 "/usr/include/term.h" 2 3 4
< # 80 "/usr/include/term.h" 3 4
---
> # 48 "/usr/include/term.h" 2
> # 80 "/usr/include/term.h"
3007,3008c3009,3010
< # 81 "/usr/include/term.h" 2 3 4
< # 673 "/usr/include/term.h" 3 4
---
> # 81 "/usr/include/term.h" 2
> # 673 "/usr/include/term.h"
3041c3043
< # 729 "/usr/include/term.h" 3 4
---
> # 729 "/usr/include/term.h"
Различный флаг в препроцессоре генерирует комментарии к коду, что делает разницу
Компилятор GCC cc1
будет использовать информацию, защищенную препроцессором, для генерации местоположения исходного кода сообщения об ошибке, а также отладочную информацию, которая будет использоваться для gdb в будущем.
Для следующего формата:
# line-number "source-file" [flags]
Знаки 3
и 4
флагов означают:
- 3: Следующий текст поступает из файла заголовка системы (
#include <>
vs#include ""
) -
4: Следующий текст следует рассматривать как обернутый в неявный блок
extern "C"
.Дополнительные сведения о различных типах этих флагов см. в этой ссылке.
Следовательно, для кода без полностью указанного пути cc1
компилятор будет рассматривать его как системный заголовочный файл и предположим, что системный код в основном верен, а затем просто выводит сообщение об ошибке кода пользователя. Вот почему сообщение об ошибке короче.