Попытка использовать макросы препроцессора для создания включаемых путей

Поэтому я думаю, что то, что я пытаюсь сделать, просто невозможно в GCC из-за расширения макросов, которое должно привести к токену препроцессора. Это отлично работает в MSVC++, чего бы это ни стоило, но я не могу найти сопоставимого

Поэтому я думаю, что это невозможно в GCC (отлично работает в VC++) из-за расширения макросов, которые должны быть токенами препроцессора и тем, что считается разделителем между токенами.

Я пытаюсь связать определенную версию библиотеки, в этом примере это Lua 5.3.1. У меня есть файлы, извлеченные в мою исходную папку, чтобы их можно было найти в подпапке «lua-5.3.1\src», и я хотел бы написать макрос, который я могу использовать для префикса файлов заголовков с этим путем. Что-то простое, например LUA_PATH(_file), которое расширится до "lua-5.3.1/src/_file". Обычно я бы просто использовал флаги компилятора, чтобы указать другую подпапку для поиска, но из-за того, как настроены проекты, над которыми я работаю, это именно то, что я не могу сделать и что я пытаюсь найти другой путь необходимость поддерживать включаемые пути повсюду.

Вот небольшой файл, который я написал (он не компилируется, но я могу запустить его через cpp, чтобы посмотреть, что он мне даст)

#define LUASRC lua-5.3.1/src/
#define STRINGIFY(_s) #_s
#define ADDLUAPATH(_path, _file) STRINGIFY(_path ## _file)
#define EVALUATOR(_path, _file) ADDLUAPATH(_path,_file)
#define LUA_PATH(_file) EVALUATOR(LUASRC,_file)

void main (void)
{
        OUTPUTOFMACROHERE => LUA_PATH(lua.h)
}

Это дает мне следующий результат запуска cpp в файле

$ cpp temp.c
# 1 "temp.c"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "temp.c"
void main (void)
{
temp.c:1:29: error: pasting "/" and "lua" does not give a valid preprocessing token
 #define LUASRC lua-5.3.1/src/
                             ^
temp.c:3:44: note: in definition of macro 'ADDLUAPATH'
 #define ADDLUAPATH(_path, _file) STRINGIFY(_path ## _file)
                                            ^
temp.c:5:25: note: in expansion of macro 'EVALUATOR'
 #define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
                         ^
temp.c:5:35: note: in expansion of macro 'LUASRC'
 #define LUA_PATH(_file) EVALUATOR(LUASRC,_file)
                                   ^
temp.c:9:23: note: in expansion of macro 'LUA_PATH'
  OUTPUTOFMACROHERE => LUA_PATH(lua.h)
                       ^
 OUTPUTOFMACROHERE => "lua-5.3.1/src/lua.h"
}

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

Проблема в символе / в конце пути. Если вы возьмете / out в конце определения LUASRC и запустите его, вы получите OUTPUTOFMACROHERE => "lua-5.3.1/srclua.h" без каких-либо ошибок ... за исключением того, что путь недействителен. Я не могу найти место, куда можно поместить символ, чтобы он попал в выходную строку в кавычках. Я пытался добавить его отдельно, например, _path ## / ## _file, или переместить его в значение, переданное, например, LUA_PATH(/lua.h). Это просто жалуется на то, что с ним сочетается (src или lua) как с недопустимым токеном препроцессора.

Я пытался просто использовать строки для конкатенации препроцессора, но #include "string" "string", кажется, просто пытается включить обе эти строки как отдельные пути. Ясно, что папка не может быть открыта, и точный файл не может быть найден без поиска подпапок. Это также было результатом того, что половина переменных (путь или файл) была строкой, которую нужно добавить к другому расширенному и строковому значению. Это также является результатом простой попытки префикса моих файлов с путем, который должен быть расширен, #include LUASRC"lua.h" (в документации GCC сказано, что если он не находит ‹ или ", он рассматривает значение для расширения макроса)

Есть ли другая стратегия, чтобы заставить его любить / в определении макроса, которого мне не хватает? Хотелось бы знать.

Я использую gcc версии 4.8.2 (Ubuntu 4.8.2-19ubuntu1).

РЕДАКТИРОВАТЬ: Логика, чтобы на самом деле сделать это, но более важные причины, по которым этого не делать, приведены в ссылке на ответ, отмеченный ниже. Однако для быстрой справки обо всем, вот как в итоге выглядел мой маленький файл temp.c

#define LUASRC lua-5.3.1/src/
#define EXPAND(_a)              _a
#define STRINGIFY(_s)           #_s
#define EVALUATOR(_args)        STRINGIFY(_args)
#define LUA_PATH(_file)         EVALUATOR(EXPAND(LUASRC)EXPAND(_file))

void main (void)
{
        OUTPUTOFMACROHERE => LUA_PATH(lua.h)
}

person James    schedule 01.09.2015    source источник


Ответы (1)


Дело не в том, что «gcc считает это ошибкой». Это это ошибка. («Если результат [конкатенации] не является допустимым токеном предварительной обработки, поведение не определено.», C11 6.10.3.3/3).

Но это не имеет значения, потому что вы можете преобразовать более одного токена в строку; нет необходимости конкатенировать. Вам просто нужно следить за пробелами.

Для примера см. https://stackoverflow.com/a/32077478/1566221.

person rici    schedule 01.09.2015
comment
Спасибо за ответ, и я взгляну на другой пример. На самом деле это не одна из многих вкладок SO, которые я пока открыл, чтобы помочь с поиском этого. И я понимаю, что компилятор буквально следует спецификациям того, что он должен делать, и с помощью собственных обозначений документации очищает то, что он раньше позволял делать. Мне просто кажется странным, что то, что может быть определено как действительный токен в этом случае, если остальная часть расширения макроса продолжается, вместо этого останавливается и остается недействительным и, следовательно, неопределенным. - person James; 02.09.2015