Функция с переменным числом аргументов в C и дизайн-ориентированный вопрос - PullRequest
1 голос
/ 11 августа 2009

У меня есть функция C с именем SetParams(...) с переменным числом аргументов. Эта функция устанавливает статическую структуру данных (назовем ее Data). SetParams используется с парами аргументов, например, SetParams("paramA", paramA_value, "paramB", paramB_value) и т. Д. Его также можно вызывать много раз, e.g.

SetParams("paramA", paramA_value);
SetParams("paramB", paramB_value);
...

Когда все «параметры» установлены, вызывается другая функция (назовем ее Execute), которая не принимает аргументов:

Execute();
// uses data from static 'Data' and performs error_handling and execution

Мне было интересно, смогу ли я структурировать этот вид кода более объектно-ориентированным способом. Итак, я хотел бы получить несколько советов, особенно для обработки ошибок, поскольку некоторые пары аргументов могут противоречить другим.

Ответы [ 4 ]

2 голосов
/ 06 октября 2009

Общая практика создания объектно-ориентированного дизайна в C заключается в том, что для каждого имеющегося у вас метода вы передадите ссылку на структуру, которая используется для хранения всех переменных-членов классов. Другими словами в C ++, где у вас есть listObj.clear(), у вас есть в C list_clear(&listObj).

Это немного уродливо, но это необходимо, если вы не хотите использовать статические переменные-члены и ограничить реализацию только один раз.

В приведенном ниже примере обратите внимание, как в каждом методе передается ссылка на struct ParamUtilObj.

// --- paramUtil.h

// Stores all the objects member variables (public and private)
struct ParamUtilObj {
  int paramCnt;
  char param1[25];
  char param2[25];
  ...
};

bool paramUtil_initialize( struct* ParamUtilObj pData );
bool paramUtil_addParam( struct* ParamUtilObj pData, const char* pKey, const char* pValue );
bool paramUtil_execute( struct* ParamUtilObj pData);

Относительно вариадических методов. Я постараюсь избежать их, если это возможно, и просто добавлю их по одному за раз. Бизнес-логика для проверки параметров - это, на мой взгляд, совершенно другая тема. Мне нужно больше информации, чтобы рекомендовать лучший подход. Но ... Мне кажется, так как вам придется выполнять проверку, например, если (MethodA), а затем проверить наличие какого-либо другого аргумента ... может быть проще создать несколько методов SetParam для каждого MethodType, который пользователь можно указать в сценарии.

1 голос
/ 11 августа 2009

Я бы порекомендовал использовать связанный список для хранения ваших параметров и поместить все ваши методы как указатели функций на структуру.

struct MyClass {
  struct LinkedList* params;
  void (*setParams)(...);
  void (*execute)()
}

связанный список будет парой ключ-значение

struct LinkedList {
   struct LinkedList *next;
   char * key;
   char * value;
}
0 голосов
/ 11 августа 2009

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

0 голосов
/ 11 августа 2009

Я не знаю, как у вас реализованы ваши SetParams, начиная от звука, который он выполняет, немного анализируя и сохраняя, и перенаправляя обработку ошибок вниз к вызову Execute. Поскольку вы используете аргументы переменной длины, используете ли вы макросы va_ *? Выполнение со строкой форматирования может позволить вам вставить обработку ошибок в ваш вызов SetParams и позволить Execute просто перебирать значения и делать свое дело.

Обычно, если у вас есть функция, которая обрабатывает параметры настройки, она должна быть там, где вы управляете ошибками, связанными с настройкой параметров. Ошибки, возникающие при выполнении команды, должны быть исправлены в функции execute.

...