Передача / получение строк через интерфейс C в программном обеспечении C ++ - PullRequest
0 голосов
/ 29 мая 2018

Я не знаком с C, но мне нужно написать интерфейс C для моего программного обеспечения C ++, чтобы доставить его в виде динамической библиотеки.Что касается классических практик , у меня есть два вопроса:

  1. Каковы классические способы передачи и получения строк и кто несет ответственность за память?
  2. это хорошая идея всегда резервировать возвращаемое значение для кода ошибки, а затем получать значения с указателями в аргументах?Если нет, то почему?

Вот пример, иллюстрирующий мои вопросы с помощью кода, который я впервые представляю:

int define_new_population(int* id)
{
  // all_pop is a std::map<int,std::vector<boost::shared_ptr<Element>>>
  *id = generate_id();
  all_pop[*id] = std::vector<boost::shared_ptr<Element>>();
  return 0;
}

int add_element_type1_in_pop(int pop_id, const char* name, double lower_bound, double upper_bound)
{
  if(all_pop.find(pop_id) == all_pop.end())
    return ERROR_CODE_WRONG_ID;
  const std::string str_name(name);
  try { all_pop[pop_id].push_back(boost::shared_ptr<Element>(new ElementType1(str_name, lower_bound, upper_bound))); }
  catch(...) { return ERROR_CODE_FOO; }
  return 0;
}

int add_element_type2_in_pop(int pop_id, const char* name, double reference)
{
  if(all_pop.find(pop_id) == all_pop.end())
    return ERROR_CODE_WRONG_ID;
  const std::string str_name(name);
  try { all_pop[pop_id].push_back(boost::shared_ptr<Element>(new ElementType2(str_name, reference))); }
  catch(...) { return ERROR_CODE_BAR; }
  return 0;
}

int get_population_size(int pop_id, int* pop_size)
{
  if(all_pop.find(pop_id) == all_pop.end())
    return ERROR_CODE_WRONG_ID;
  *pop_size = (int)all_pop[pop_id].size();
  return 0;
}

int get_element_name(int pop_id, int elem_index, char** name)
{
  if(all_pop.find(pop_id) == all_pop.end())
    return ERROR_CODE_WRONG_ID;
  if(elem_index >= (int)all_pop[pop_id].size())
    return ERROR_CODE_OUT_OF_RANGE;
  const std::string& str_name = all_pop[pop_id][elem_index].getName();
  *name = malloc(sizeof(char) * (str_name.length() + 1));
  strcpy(*name, str_name.c_str());
  return 0;
}

1 Ответ

0 голосов
/ 29 мая 2018

Я могу хотя бы дать несколько советов.

  • Кто освобождает память (вызывающий или DLL), должен быть четко определен в API.
  • Имейте в виду, что если вызывающий и вызываемый абонентыскомпилированы отдельно с разными версиями библиотеки Windows std C, malloc и бесплатными с разными версиями C lib / runtime, как правило, не будут работать.Если вы можете автоматизировать это, предоставив пользователю API обратный вызов «без памяти», который можно использовать с RAII, это хороший способ.Приведите пользователю API простые примеры для подражания.
  • Если у вас есть полный контроль над библиотекой DLL и вызывающей стороной, вы даже можете передавать исключения C ++ через границы DLL, намного чище, чем коды ошибок, но если вы точно не знаете, что именновы делаете, более хрупким.
  • Вы можете даже иметь API C ++ (не чистый C), используя механизм Windows / Visual Studio «все просто работает».Это просто работает и даже распространяется на C ++ / CLI и C # смешанные кодовые базы.Вот еще немного документации: неявный PInvoke

Что касается вопроса о резервировании возвращаемого значения для кодов ошибок и отправке указателей (или, при необходимости, указателей на указатели), то естьобычно хорошая и очень общая техника.Конечно, если вы создаете C ++ API, современный способ - использовать вместо этого совершенные ссылки пересылки и rvalue.

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