функциональные макросы и переменные - PullRequest
2 голосов
/ 24 февраля 2020

По какой-то непонятной причине в моем коде есть что-то вроде:

#define pippo(x) printf("%d",x)
...
... many lines down in the code
...
int pippo = 0;

Один и тот же идентификатор pippo был использован как для функционально-подобного макроса, так и для имени переменной! Помимо путаницы, которая могла возникнуть у плохого сопровождающего, мне было интересно, допустимо ли это стандартом.

И C99, и C11 (в 6.10.3.) Говорят:

10 [...] Каждый последующий экземпляр функционально-подобного имени макроса, за которым следует a (в качестве следующего токена предварительной обработки вводится последовательность токенов предварительной обработки, которая заменяется списком замены в определении [...]

Они не говорят, что происходит, если имя макроса, похожее на функцию, , а не , за которым следует '(', и я беспокоюсь, что какой-то компилятор может посчитать, что это ошибка (или может просто выдать предупреждение).

Не слишком ли я беспокоюсь?

Ответы [ 2 ]

6 голосов
/ 24 февраля 2020

Экземпляры имени функционально-подобного макроса, за которыми не следует (, не заменяются.

Использование имен, таким образом, не является нарушением ограничений в стандарте C. Стандарт даже дает пример использования этого поведения. C 2018 7.1.4 1, обсуждая стандартные библиотечные функции и их потенциальные реализации как функционально-подобные макросы (в дополнение к определению как функции), говорится:

… Любое макроопределение Функция может быть подавлена ​​локально, заключив имя функции в круглые скобки, потому что имя не сопровождается левой круглой скобкой, которая указывает на расширение имени макрофункции. По той же причине syntacti c разрешается брать адрес библиотечной функции, даже если он также определен как макрос ...

Компилятор может выдавать предупреждение (хотя это может произойти хотите подавить это предупреждение, когда имя макроса является библиотечной функцией, используемой в соответствии со стандартом C (см. выше), но ни G CC 9.2, ни Clang 11.0.0 этого не делают, даже если включены все предупреждения.

3 голосов
/ 24 февраля 2020

5.1.1.2, пункт 4, определяет, как препроцессор «вызывается», если вы будете:

Выполняются директивы предварительной обработки, расширяются вызовы макросов и выполняются выражения унарного оператора _Pragma. [...] Затем все директивы предварительной обработки удаляются.

Таким образом, это означает, что все, что не затронуто препроцессором, остается в покое, включая любые pippo, за которыми не следует ( .

...