Переменные списки параметров в C ++ и C - PullRequest
4 голосов
/ 07 октября 2009

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

typedef struct {
    char *name;
    int argc;
    void (*func) ();
} FUNCTION;

Каким-то образом через func может быть передано переменное число аргументов.

RESULT *param[10];

if (Root->Function->argc < 0) {
    /* Function with variable argument list:  */
    /* pass number of arguments as first parameter */
    Root->Function->func(Root->Result, argc, &param);
} else {
    Root->Function->func(Root->Result, param[0], param[1], param[2], param[3], param[4], param[5], param[6],
                         param[7], param[8], param[9]);
}

Я даже не уверен, как это можно сделать в Си, если честно. Объяснение было бы превосходным. Это может быть сделано в C ++?

Ответы [ 5 ]

8 голосов
/ 07 октября 2009

var args - это то, что вы ищете. Работает как на C, так и на C ++. Это то, что используется для printf(), например:).

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

6 голосов
/ 07 октября 2009

На самом деле я собираюсь пойти против всех здесь, и вашего желания.

Многоточие неверно. Он считался незаменимым в Си, но с тех пор мы научились лучше.

Действительно, в C ++ есть способы добиться гораздо большего, используя объекты и, например, функциональные объекты.

То, что вы ищете, это шаблон команд .

Создайте базовый класс с именем «Command» (интерфейс с методом execute ()), затем для каждой из «функций», которые вы хотите поместить в «void (* func) ()», вы создаете производный класс.

Теперь ваш код будет выглядеть так:

std::vector<RESULT*> param(10, NULL);

if (Root->Function->argc < 0) {
    /* Function with variable argument list:  */
    /* pass number of arguments as first parameter */
    Command1* aCommand = new Command1(Root->Result);
    aCommand->set(Root->Result, argc, &param);
    Root->Function->command = aCommand;
    Root->Function->command->execute();
} else {
    Command2* aCommand = new Command2(Root->Result);
    aCommand->set(Root->Result, param[0], param[1], param[2], param[3], param[4], param[5], param[6], param[7], param[8], param[9]);
    Root->Function->command = aCommand;
    Root->Function->command->execute();
}

Здесь вам не нужно многоточия, потому что каждый объект команды является специализированным и точно знает, какие параметры ему нужны (число И типы).

Шаблон команд позволяет вам пользоваться всеми преимуществами «...» (многоточия) без неудобств. Ну, конечно, некоторые скажут, что это потеря времени, так как они все равно не делают ошибок, поэтому им не нужно больше печатать ... к сожалению, я не настолько умен, поэтому предпочитаю определять ограничения (число, типы , утверждений) и пусть компилятор применяет их для меня.

1 голос
/ 07 октября 2009

Вы можете сделать это в C ++, используя ... в списке аргументов. Посмотрите здесь для объяснения. Но я думаю, что будет лучше, если вы просто передадите вектор param своей функции.

0 голосов
/ 07 октября 2009

Лично, когда дело доходит до оценки AST для выражения, я склонен использовать язык, специфичный для предметной области, для генерации иерархии структур узла AST и набора операций множественной диспетчеризации. У меня есть свой DSL для этого, но идея была украдена из treecc . Многие проблемы уходят, потому что вам не нужно иметь один класс узла или одну функцию оценки узла - а поскольку DSL выполняет различные проверки для вас, вы в основном избегаете замены этих проблем на другие.

treecc может генерировать вывод C или C ++ (или несколько других языков) IIRC. Это очень похоже на использование флекса или бизона. Сгенерированный код немного наивен, и вскоре вы захотите получить больший контроль над наследованием, но он работает довольно хорошо.

0 голосов
/ 07 октября 2009

Помните, что функция - это просто еще один адрес, который при вызове start берет входные параметры из стека. Поэтому, когда вы объявляете FUNCTION, вы просто сохраняете адрес этой функции. С этим адресом функция может быть вызвана позже с другими параметрами. Да, это может быть сделано в C ++ с использованием списков аргументов, однако реализация зависит от того, как вы хотите, чтобы это обрабатывалось.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...