Как включить новую строку в макрос C++ или как использовать шаблоны C++, чтобы сделать то же самое?
Я видел следующий вопрос: Как создать новую строку в макросе cpp?
Позвольте мне дать краткое требование о необходимости новой строки в препроцессоре C++. Я работаю над компилятором ARM Realview 3.1 над кодом, который использует встроенный ассемблерный код с кодом C++.
#define DEFINE_FUNCTION(rtype, op, val) \
__asm rtype nt_##op(void*) { \
str lr, [sp, ##val];bl vThunk_##op;ldr lr, [sp,##val];bx lr; \
} \
void vThunk_##op(void*)
DEFINE_FUNCTION(void*, mov_lt, #0x04)
{
// do some operation
}
Вышеупомянутый макрос объявляет встроенную функцию сборки, которая принудительно требует новой строки между каждым оператором в теле функции.
Я думаю, это потому, что текст в теле функции отправляется вслепую ARM-ассемблеру компилятором ARM.
Почему препроцессор C++ до сих пор не поддерживает многострочные замены? а также я не могу использовать # в строке замены. например, для такого рода сборки,
str lr, [sp, #0x04]
Я перепробовал много методов и способов, но ничего не получилось. Ассемблер / компилятор ARM настолько прост, что в GCC нет API, подобного asm volatile.
Макрос DEFINE_FUNCTION используется во многих местах, поэтому не может его игнорировать.
Итак, в крайнем случае подумайте о следующих решениях:
- Использование препроцессора m4 вместо препроцессора C++
- Используйте шаблоны C++, чтобы как-то добиться этого, и замените DEFINE_FUNCTION, используя grep/sed
Может кто-нибудь дать мне указатели или способы сделать вышеупомянутые вещи? Я не могу использовать любой компилятор, кроме компилятора ARM Realview 3.1.
Мне нужно расширение, как показано ниже, с новой строкой для, DEFINE_FUNCTION(void*, mov_lt, #0x04) {}
,
__asm void* nt_mov_lt(void*) {
str lr, [sp, 0x04];
bl vThunk_mov_lt;
ldr lr, [sp,0x04];
bx lr;
}
void vThunk_mov_lt(void*)
{
// do something
}
4 ответа
Я решил вышеупомянутую проблему с помощью препроцессора GNU m4.
m4_define('DEFINE_FUNCTION','
__asm rtype nt_$2(void*) {
str lr, [sp, $3];
bl vThunk_$1;
ldr lr, [sp,$3];
bx lr;
}
void vThunk_$2(void*)')
DEFINE_FUNCTION(void*, mov_lt, 0x04)
{
}
Предварительная обработка приведенного выше кода с использованием m4 решила мою проблему с требованием новой строки в коде. Запустил m4 -P в качестве события предварительной сборки, чтобы исходный файл обрабатывался еще до того, как начался этап препроцессора C и стадии компиляции.
Спасибо за помощь и извиняюсь за то, что много путаю. Но в последних компиляторах C++ действительно есть место для хорошего препроцессора макросов.
Каждая газовая версия имеет свой символ замены новой строки, например, AVR имеет $ look для символа газовой версии ARM
Я не знаю различных компиляторов C и C++ для ARM, но следующее работает в 2022 году как минимум с компиляторами Microsoft для Windows x86/x64, а также с компиляторами Open Watcom (даже для DOS):
#define MY_MACRO { \
_asm { \
_asm MOV AX, 0 \
_asm MOV BX, 1 \
} \
}
Препроцессор превращает это в одну строку, удаляя символы продолжения и символы новой строки, но каждый
_asm
токен разделяет инструкции, как если бы была новая строка.
Чтобы еще раз подчеркнуть, я понятия не имею об ARM, и синтаксис для GCC x86/x64 все равно отличается, но, возможно, вы сможете применить эту идею к своей проблеме.
PS Я знаю, что крайние фигурные скобки лишние, но я предпочитаю именно их при написании макросов.
Ваш пример очень запутанный, но разве это не сработает?
#define DEFINE_FUNCTION(rtype, op, val) \
__asm rtype nt_##op(void*) { \
str lr, [sp, val];\
bl vThunk_##op;\
ldr lr, [sp,val];\
bx lr;\
}\
void vThunk_##op(void*)
и когда называется как
DEFINE_FUNCTION(void*, mov_lt, 0x04) // notice no # here
{
// do some operation
}
вы получите
__asm void* nt_mov_lt(void*) {
str lr, [sp, 0x04];
bl vThunk_mov_lt;
ldr lr, [sp,0x04];
bx lr;
}
void vThunk_mov_lt(void*)
{
// do something
}
это именно то, что вы просите.