Поведение __LINE__ при использовании в макросе

Почему __LINE__ оценивает по-разному в зависимости от того, используется ли он внутри функционального макроса или обычной функции?

Например:

#include<stdio.h>

#define A() printf("%d
",__LINE__);

int main(void) {
/* 6 */  A();
/* 7 */  A(
/* 8 */    );
/* 9 */  printf("%d
",__LINE__
/* 10 */  );
}

Я ожидаю получить:

6
7
9

Но вместо этого мы получаем (используя clang-1000.10.44.4):

6
8
9

Обратите внимание, что в функционально-подобном макросе, разбросанном по строкам 7 и 8, используется последняя занятая строка, а не первая.

Документация GCC содержит подробные сведения: https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html.

Почему меня это волнует? Я пишу парсер, который должен найти номера строк всех экземпляров макроса A таким образом, чтобы он соответствовал тому, что __LINE__ вернет. Гораздо сложнее найти последнюю строку использования макроса, чем первую, из-за необходимости разбора возможно экранированных аргументов.

Всего 1 ответ


Реализация C не заменяет макрос A() пока не увидит закрытие ) . Это ) появляется в строке 8, так что это точка, в которой происходит замена макроса.

Особенности __LINE__ отношении замены макросов не очень хорошо определены стандартом C. Вы, вероятно, не должны полагаться на конкретное поведение здесь. Конечно, реализация C не может заменить макрос A() пока он читает только до строки 7, поскольку он еще не знает, что будет. Как только он увидит закрытие ) , тогда, когда он заменяет макрос, он может считать, что токены замещения встречаются в строке 7, в строке 8 или в некоторой смеси - стандарт C не является специфическим в этом отношении; Номера строк в значительной степени не имеют отношения к семантике C на этом этапе, и макрос __LINE__ в значительной степени удобен для отладки и других разработок, а не для производственных программ (хотя он может иметь некоторое использование для них).

В printf реализация C распознает макрос __LINE__ как только видит конец строки. (На самом деле, синтаксический анализ более сложен; входные данные были токенизированы, но эффект заключается в __LINE__ токен __LINE__ распознается, когда __LINE__ символ конца строки.) Он находится в строке 9, поэтому он заменяется на 9 . Тот факт, что это аргумент для printf имеет значения. Реализация C не имеет процесса printf для замены токена __LINE__ который появляется в строке 9; они не взаимодействуют.


Есть идеи?

10000