2014-11-28 2 views
0

Учитывая этот кусок C код:#line и строковый литерал конкатенации

char s[] = 

"start" 

#ifdef BLAH 
"mid" 
#endif 

"end"; 

что следует вывод препроцессора быть? Другими словами, что должен получать и иметь возможность обрабатывать фактический компилятор? Чтобы сузить возможности, давайте придерживаться C99.

Я вижу, что некоторые препроцессоры выход это:

#line 1 "tst00.c" 
char s[] = 

"start" 
#line 9 
"end"; 

или это:

# 1 "tst00.c" 
char s[] = 

"start" 




# 7 "tst00.c" 


"end"; 

НКУ -E выводит это:

# 1 "tst00.c" 
# 1 "<command-line>" 
# 1 "tst00.c" 
char s[] = 

"start" 





"end"; 

И НКУ прекрасно подходит компилирование весь вышеуказанный предварительно обработанный код даже с -fpreprocessed это означает, что дальнейшая предварительная обработка не должна выполняться, поскольку все это уже сделано.

Путаница проистекает из этой формулировки стандарта 1999 C:

5.1.1.2 Translation phases 
1 The precedence among the syntax rules of translation is specified by the following 
    phases. 
... 
4. Preprocessing directives are executed, macro invocations are expanded, and 
_Pragma unary operator expressions are executed. ... All preprocessing directives are 
then deleted. 
... 
6. Adjacent string literal tokens are concatenated. 
7. White-space characters separating tokens are no longer significant. Each 
preprocessing token is converted into a token. The resulting tokens are syntactically 
and semantically analyzed and translated as a translation unit. 

Другими словами, это законно для #line директивы появляться между соседними строковых литералов? Если это так, это означает, что фактический компилятор должен выполнить еще один раунд конкатенации строковых литералов, но это не упоминается в стандарте.

Или мы просто имеем дело с нестандартными реализациями компилятора, включенными gcc?

ответ

1

#line или # 1 строки, которые вы получаете из GCC -E (или совместимого инструмента), добавляются ради читателей и любых инструментов, которые могут пытаться работать с текстовой формой вывода препроцессора. Они просто для удобства.

В общем, да, директивы могут отображаться между конкатенированными строковыми буквами. #line ничем не отличается от #ifdef в вашем примере.

Или мы просто имеем дело с нестандартными реализациями компилятора, включенными gcc?

-E и -fpreprocessed режимы не стандартизированы. Стандартный препроцессор всегда передает свой вывод в компилятор, а не в текстовый файл. Кроме того:

Выход препроцессора не имеет стандартного текстового представления.

Причина для вставки #line директивы так, что любые __LINE__ и __FILE__ макросов, которые можно вставить в уже препроцессоре файл перед предварительной обработкой его снова, будут расширяться правильно. Возможно, при компиляции такого файла компилятор может заметить и использовать значения при отправке сообщений об ошибках. Использование «предварительно обработанных текстовых файлов» нестандартно и обычно не рекомендуется.

+0

Я не уверен насчет \ _ \ _ LINE \ _ \ _ и \ _ \ _ FILE \ _ \ _. Они должны были быть расширены во время предварительной обработки.Кроме того, #line не только для читателей с запрограммированным кодом. Достойному компилятору нужны эти директивы #line для создания значимых ошибок, указывающих местоположение проблемы в исходном коде. –

+0

@AlexeyFrunze Я сказал: «вы можете вставить в уже предварительно обработанный файл». Нет, компилятор не должен позволять '# строке' определять, как сообщения об ошибках сообщаются в сообщениях. – Potatoswatter

+0

Да, я думаю, ключ состоит в том, что токеты предварительной обработки становятся токенами, а интерфейсы на этой границе не стандартизированы. –

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