яблоко cpp прерывает вставку макропараметров - PullRequest
1 голос
/ 01 августа 2020

Составьте следующий тест. cpp

# define TopLevelProject X11

#define Concat3(a,b,c) a/**/b/**/c

# define ProjectRulesFile Concat3(<,TopLevelProject,.rules>)

#include ProjectRulesFile

cpp -I. test. cpp

Ожидается, что будет сгенерирован оператор include

# 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.cpp"
# 10 "test.cpp"
# 1 "./X11.rules" 1
# 11 "test.cpp" 2



# 1 "./X11.rules" 1
# 15 "test.cpp" 2

Обратите внимание, что строка "./ X11 .rules " действительно выводится

Однако яблочный clang cpp дает результат

# 1 "test.cpp"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 361 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "test.cpp" 2


test.cpp:7:10: fatal error: ' X11 .rules' file not found
#include ProjectRulesFile
         ^~~~~~~~~~~~~~~~
test.cpp:5:35: note: expanded from macro 'ProjectRulesFile'
# define ProjectRulesFile       Concat3(<,TopLevelProject,.rules>)
                                ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:3:24: note: expanded from macro 'Concat3'
#define Concat3(a,b,c) a/**/b/**/c
                       ^~~~~~~~~~~

1 error generated.

Обратите внимание на искаженное имя файла 'X11 .rules'

Apple cpp вставляет пробел перед первым параметром и еще один между вторым и третьим параметрами макроса Concat3.

Все версии g cc, clang и инструментов msdev выполните правильную замену текста.

Но

Все версии cpp от Apple, например, распространяемые xcode, имеют эту ошибку.

Есть ли какая-то схема конкатенации параметров макроса, которую я мог бы использовать для написания макроса Concat3 , чтобы он работал под cpp?

Спасибо

1 Ответ

3 голосов
/ 02 августа 2020

Concat3(a,b,c) a/**/b/**/c - это древний, предстандартный, давно устаревший метод объединения данных. Обычно он не работает ни с чем современным (то есть с 1990 года или около того). Он может работать специально для конкатенации имен заголовков с некоторыми компиляторами, потому что это область, определяемая реализацией.

6.10.2 / 4 Метод, с помощью которого последовательность токенов предварительной обработки между парой токенов предварительной обработки < и > или парой символов " объединяется в один токен предварительной обработки имени заголовка определяется реализацией.

Объединение все, что не является именем заголовка с этим методом, исключено.

НЕТ стандартного способа объединения имени заголовка, который работал бы для всех компиляторов. Стандартный трюк

#define CAT(a,b) CAT2(a,b)
#define CAT2(a,b) a ## b

не работает, если результат не является допустимым токеном предварительной обработки, чего нет у большинства имен заголовков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...