[C++] Вызов фукнции с ...
va_list и иже с ним ?
Как "разобрать" то, что мне пришло на вход я понимю. Я не понимаю, как вызвать функцию A. Вызов ее с параметром "va_list" вызовет ее не со стеком, в котором N ссылок на void * а с ссылкой на память, где лежат ссылки на void *. Если иметь доступ в A, то да, можно добавить ей такой интерфейс. Но пока мне интересно решение, когда я не имею никакого отношения к A и не имею право ее менять.
Я бы сделал кучу перегруженных функций с разным числом аргументов...
черт, попутал. Я ею пользовался для впринтфа там все заранее готово
Это эквивалент решению 1 да? Ну то есть от switch по N он мало отличается. Разве что в одном случае я дублирую код B а выбор делает за меня компилятор на этапе компиляции, а в другом выбор делается во время работы и дублирование кода функции B нет. Мне это нравится чуть меньше, так как функция B должна торчать из либки и их будет очень много там.
Но портируемых способов решить задачу (а asm - это не портируемый способ) по-моему нет
7.5 Как написать функцию с переменным числом аргументов, которая передаетЯ бы пошел по второму варианту, но совместимости не будет. Говорят, сам va_list не вполне кроссплатформен.
их другой функции с переменным числом аргументов?
О: В общем случае задача неразрешима. В качестве второй функции нужно
использовать такую, которая принимает указатель типа va_list, как это
делает vfprintf в приведенном выше примере. Если аргументы должны
передаваться непосредственно (a не через указатель типа va_list и
вторая функция принимает переменное число аргументов (и нет
возможности создать альтернативную функцию, принимающую указатель
va_list то создание переносимой программы невозможно. Проблема
может быть решена, если обратиться к языку ассемблера соответствующей
машины.
То есть с asm практически никаких гарантий, что это будет работать на чем-то кроме "обычных" компов?
есть у меня сильное сомнение что это будет работать на "необычных" компах и компиляторах, но обосновать не могу
Я бы пошел по второму вариантуА я бы - по первому.
ничего не стоит написать функцию f(int,... в которой первым же делом будет вызвана функция f(int,va_list а последнюю вызывать из g
типа std::list<void*>
Просто не хотелось лезть туда, где функция A релизована.
Но видимо придется. Скорее всего так и поступлю. Просто на всякий случай хотел узнать по поводу существования "универсальных решений", которые не трогают А.
Это эквивалент решению 1 да? Ну то есть от switch по N он мало отличается. Разве что в одном случае я дублирую код B а выбор делает за меня компилятор на этапе компиляции, а в другом выбор делается во время работы и дублирование кода функции B нет. Мне это нравится чуть меньше, так как функция B должна торчать из либки и их будет очень много там.Для этих целей есть boost::preprocessor - он тебе нагенерит сколько угодно функций (почти). А то, что у тебя из либки будет торчать лишних двадцать функций - ничего страшного: у тебя из либки и так торчат все функции, которые нестатические и не в безымянном неймспейсе.
ЗЫ. Эллипсы - зло.
rsdn. Поищи там.
Но суть была такая же как и 2: на стеке выделялся кусок памяти params, потом с помощью va_list в этот кусок копировали параметры, а потом вызывалась B(N, params).
А я видел решение на с++ на Но суть была такая же как и 2: на стеке выделялся кусок памяти params, потом с помощью va_list в этот кусок копировали параметры, а потом вызывалась B(N, params).
Оставить комментарий
deniska
Тут все немножко упрощено, но суть примерно та.В нашей библиотеке есть функция
void A(int N, ...);
где N - число параметров, которые ей передадут через ... и все они типа (void *).
Хочется научиться из фунции B с тем же интерфейсом (после некоторой работы) вызвать функцию A с теми же параметрами.
Как это сделать - непонятно. Пока я вижу два пути это сделать
1. Написать case для N и разобрать в ручную случаи, когда N, например, не превосходит 16. В случае, когда N > 16 выкинуть пользователю предупреждение, чтобы не стоит ее вызывать с таким количеством параметров и пусть сделает как-нить подругому.
2. Через asm{} перепихать в стэк в цикле весь тот кусок памяти, что я получил на вход, далее вызвать по адресу функцию А (тоже через asm{}) и подчистить за собой стэк. Это решение относительно N более универсальное, но моему эстетическому чувству прекрасного что-то в нем не нравится. Точнее не нравится то, что такая игра со стеком имеет свойство очень сильно все испортить если будет какая-то неожиданная ошибка (например, надо ловить все exception из А и глубже, чистить стэк и перекидывать исключение дальше). Так же я не до конца уверен, что стэк на всех машинах работает одинаково и эта штука будет работать на странных машинах (а мы частенько работаем на таких).
Есть какие-нить другие варианты, как это можно сделать не переписывая функцию А?