Получение параметров функции эллипса без начального аргумента

Поэтому я делал собственный синтаксический анализатор для языка сценариев, и я хотел иметь возможность передавать только аргументы эллипсов. Мне не нужна или не нужна начальная переменная, однако Microsoft и C, похоже, хотят чего-то другого. К вашему сведению, см внизу для информации.

Я посмотрел на определения va_ *

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

и часть, которую я не хочу, v в va_start. Как небольшой опыт, я хорошо разбираюсь в goasm и знаю, как работает стек, поэтому я знаю, что здесь происходит. Мне было интересно, если есть способ получить базу стека функций без использования встроенной сборки.

У меня были идеи:

#define im_va_start(ap) (__asm { mov [ap], ebp })

и т.д … но на самом деле я чувствую, что это грязно, и я делаю это неправильно.

struct function_table {
const char* fname;
(void)(*fptr)(...);
unsigned char maxArgs;
};
function_table mytable[] = {
{ "MessageBox", &tMessageBoxA, 4 } };

… некоторая функция, которая сортирует через const char *, переданную ей, чтобы найти соответствующую функцию в mytable, и вызывает tMessageBoxA с параметрами. Кроме того, аргумент maxArgs предназначен для проверки того, что отправляется правильное количество параметров. У меня есть личные причины, по которым я не хочу отправлять это в функцию, но пока мы можем просто сказать, что это потому, что мне любопытно.

Это всего лишь пример; Пользовательские библиотеки — это то, что я буду реализовывать, чтобы они не просто вызывали WinAPI.

void tMessageBoxA(...) {
// stuff to load args passed
MessageBoxA(arg1, arg2, arg3, arg4);
}

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


редактировать: спасибо за ввод, кажется, это было невозможно.

Мое исправление закончилось тем, что

    #define im_va_start(ap) {\
__asm push eax\
__asm mov eax, ebp\
__asm add eax, 8h\
__asm mov ap, eax\
__asm pop eax\
}

И тогда я могу продолжить как обычно.

Что касается того, почему мне это нужно, я делаю некоторые (уникальные) трюки read: unsafe и использую массив struct с указателем на функцию, как определено выше. Поскольку каждая функция уникальна, и большинство из них из моей пользовательской библиотеки, они имеют … различное поведение. Я не знаю, как это объяснить, но я выпущу источник, когда закончу POC.

Я не очень беспокоюсь о переносимости, так что придется работать. Также для подсчета аргов я сделал:

#define im_va_count(ap, num, t) {\
for(num = 0; *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) > 0; ++num){ }\
--num;\
im_va_start(argptr);\
}

который работает для меня. Если кому-то интересно …

2

Решение

К сожалению, это невозможно, стандарт C говорит:

Функция может быть вызвана с переменным числом аргументов разных типов. Как
описанный в 6.9.1, его список параметров содержит один или несколько параметров.

И ... не считается «одним или несколькими параметрами». В дальнейшем,

va_start макрос должен быть вызван перед любым доступом к безымянным аргументам.

Что это надо называть как

va_start(va_list, parmN)

И это

Параметр parmN является идентификатором самого правого параметра в переменной
список параметров в определении функции (тот, что перед , ...).

Таким образом, как вы можете видеть, у вас не может быть функции с переменными числами без хотя бы одного параметра перед многоточием в стандартном C ++. Неподвижный сборочный трюк — самый близкий, который вы можете прийти.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]