2016-10-14 14 views
3

Согласно стандарту C11,Cross-file #if и #endif - должно ли оно быть законным?

предварительной обработки директивы формы

# включают «д-символ последовательности» Новая линия

приводит к замене этой директивы по всему содержимому исходный файл, идентифицированный указанная последовательность между "разделителями

Так что, если у меня есть файл заголовок test.h содержащий:.

#endif 

И исходный файл, содержащий test.c:

#if 1 
#include "test.h" 

Не должно пройти этап предварительной обработки в соответствии со стандартом, заменив содержание test.h на месте?

Но я не могу сделать это с clang, который говорит:

In file included from test.c:2: 
./test.h:1:2: error: #endif without #if 
#endif 
^ 
test.c:1:2: error: unterminated conditional directive 
#if 1 
^ 
2 errors generated. 

Так что же такое поведение, что стандарт указан?

ответ

6

Если вы читаете, например, this C++ #include reference включенный файл сначала запускается через translation phases от одного до четырех, а phase four запускает препроцессор (рекурсивно).

Это значит, что файл, который вы указали, должен быть заполнен в отношении #if и #endif.

Это происходит и в C.


После прочтения спецификации C11 (ISO/IEC 9899: 2011 [2012]), что я думаю это происходит:

Компилятор находится в фазе препроцессора (phase 4) и оценивает #if 1 препроцессор. Условие оценивается как true, поэтому он входит в блок внутри условия. Существует директива #include "test.h".

Когда компилятор обрабатывает директиву include, он временно прекращает обработку текущего файла для обработки прилагаемого файла. Эта обработка включенного файла проходит через фазу 1 - 4 компиляции (включительно), прежде чем продолжить с текущим исходным файлом.

Когда обработка самого включаемого файла заголовок приходит к 4-й фазе и начинает обрабатывать #endif директивы, то он не идет вверх в рекурсивной стеке включения, чтобы найти соответствие #if, препроцессор просматривает только текущий стек-кадр (текущий файл). Поэтому вы получите первую ошибку около #if. Стандарт на самом деле ничего не говорит об этом. Все, что он говорит, в основном, состоит в том, что #if должен иметь соответствие #endif. То, что компилятор не поднимает стек включения, чтобы найти подходящее значение #if, похоже, больше детализация реализации.

В любом случае, препроцессор завершает свою обработку файла заголовка с шагом 3 в фазе 4, которая является

В конце этой фазы, все директивы препроцессора удаляются из источника.

Поэтому, когда элемент управления возвращается к предварительной обработке исходного файла, файл, который он фактически включает, не содержит директив предварительной обработки. Все, что включено, это пустой файл, в основном. И это приводит к второй ошибке, что нет #endif для #if, потому что на самом деле нет.

+1

Этот ответ ничего не объясняет. Вся препроцессия происходит в одной и той же фазе, поэтому это не помогает понять, что происходит. См. Мой ответ ниже. –

0

clang верен: такой раскол #if/#endif в разных файлах не соответствует. Это связано с тем, что препроцессор сначала просматривает остальную часть файла, чтобы найти соответствующий #endif, и только затем решает другие директивы препроцессора, которые присутствуют в условной части, которая хранится.

Это раздел 6.10.1 p6 стандарта C.

+0

Хотя мой ответ не совсем корректен, это не так. Если компилятор сканирует исходный файл, чтобы найти подходящий '# elif' /' # else'/'# endif', он вообще не будет включать заголовочный файл' 'test.h '', и единственной ошибкой будет один о unterminated '# if'. Стандарт (я прочитал C11 (издание 2012 года)) ничего не говорит о том, как компилятор должен соответствовать директиве препроцессора '# if' для' # endif'. Сканирование, которое вы упомянули, представляет собой деталь реализации, оставленную вне стандарта. –

 Смежные вопросы

  • Нет связанных вопросов^_^