Как создать определение препроцессора с использованием арифметики? - PullRequest
2 голосов
/ 24 апреля 2019

Я хочу динамически создавать литеральные строки препроцессора, в которых часть строки создается с помощью некоторой арифметики, например: math(x) x - 0x1234. Сгенерированные определения будут созданы макросом: get_tex_uniform_name(unit), а результаты будут такими же, как и следующие численно упорядоченные определения:

// texture uniform naming
#define TEX_UNIFORM_BASE_NAME       "tex"
#define TEX_UNIFORM_0               TEX_UNIFORM_BASE_NAME"0"  // "tex0" and so on
#define TEX_UNIFORM_1               TEX_UNIFORM_BASE_NAME"1"
#define TEX_UNIFORM_2               TEX_UNIFORM_BASE_NAME"2"
#define TEX_UNIFORM_3               TEX_UNIFORM_BASE_NAME"3"

Я попытался сгенерировать строку с нуля с помощью STRINGIFY (#):

#define get_tex_unit_num(unit) unit - GL_TEXTURE0
// create string literal from whatever is put in
#define STRINGIFY(x) #x
#define LITERAL_STRINGIFY(x) STRINGIFY(x)
#define get_tex_uniform_name(unit) TEX_UNIFORM_BASE_NAME LITERAL_STRINGIFY(get_tex_unit_num(unit))

// issue: result is "texunit - 0x84C0", 0x84C0 being GL_TEXTURE0

Я попытался вставить токен для работы с существующими определениями:

#define get_tex_unit_num(unit) unit - GL_TEXTURE0
#define get_tex_uniform_name(unit) TEX_UNIFORM_ ## get_tex_unit_num(unit)

// error: TEX_UNIFORM_get_tex_unit_num is undefined

И пытался заставить работать какую-то битовую маскировку:

#define TEX_UNIFORM_BASE_NAME       "tex "

#define get_tex_unit_num(unit) unit - GL_TEXTURE0
#define get_tex_uniform_name(unit) TEX_UNIFORM_BASE_NAME & (0xffffff00 + (char)get_tex_unit_num(unit))

// error: expression must have integral or unscoped enum type

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

Ответы [ 2 ]

2 голосов
/ 24 апреля 2019

Ваш первый пример кода должен работать, поэтому нет необходимости вставлять строковые литералы вместе в препроцессоре.Это также невозможно.

Это невозможно, поскольку ## объединяет два токена предварительной обработки, и результат должен быть действительным токеном предварительной обработки.Токен предварительной обработки - это имя заголовка, идентификатор, номер предварительной обработки, символьная константа, строковый литерал, пунктуатор или один символ, не являющийся пробелом.Вы не можете вставить два строковых литерала и удалить две кавычки, которые заканчиваются между ними.Однако обычно нет необходимости склеивать их вместе;достаточно просто позволить им расширяться рядом друг с другом, потому что смежные строковые литералы объединяются.

Ваш первый пример кода, который генерирует результаты вроде "tex" "0", в порядке.После предварительной обработки и перед анализом и переводом (компиляцией) соседние строковые литералы преобразуются в один конкатенационный строковый литерал.Таким образом, не будет никаких проблем приоритета или другого синтаксиса и семантики.

0 голосов
/ 02 мая 2019

Я хотел завершить этот вопрос для будущих зрителей, сославшись на вопрос, который уже отвечает на этот вопрос: Может ли препроцессор C выполнять целочисленную арифметику?

Короче говоря, препроцессор может выполнять арифметику, если он используется при оценке постоянных условий:

#if 1 + 2 == 5
#endif
#else
#endif

Но поскольку вы не можете комбинировать макрос с этим, вы не можете сделать строковые литеральные определения перед компиляцией.

...