вызов методов C++ от C

Таким образом, это было некоторое время, так как я использовал прямой C. И я нахожусь на проекте, где я работаю над API в C++. Большинство этих методов просто C так или иначе, и все возвращаемые значения являются структурами C. Кроме одного. Один метод я должен возвратить a vector<string>. Теперь вот мой вопрос. C++ methods/libraries/whatever вызываемый от C? Я спрашиваю, потому что я не знаю, собираются ли люди, использующие API, быть записью в C или C++, и я чувствую, что должен возвращать только C структуры. Это потребовало бы, чтобы я возвратил a char**, право?

Я надеюсь, что имел смысл, если нет:

tl; версия доктора - я могу назвать метод C++ от C, если это возвращает структуру C и раз так является лучшим (только?) эквивалентное возвращаемое значение vector<string> -> char**?

Обновление: методы C++ являются просто глобальными методами. Нет никаких классов или объектно-ориентированного материала в них. ЕДИНСТВЕННАЯ вещь это характерно для C++ кроме моего векторного вопроса, является некоторыми stringstreams

7
задан Falmarri 4 August 2010 в 06:37
поделиться

6 ответов

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

Эквивалент vector в C, вероятно, ближе к:

 typedef const char* c_string_type;
 typedef struct c_string_array {
     c_string_type* c_strings;
     int c_strings_count;
  } c_string_array_t;

С непрозрачными типами у вас будет что-то вроде:

 typedef void* c_string_array_t;
 int c_string_array_length(c_string_array_t array);
 const char* c_string_array_get(c_string_array_t array, int index);

Затем вы можете тайно (в реализации C ++) привести std :: вектор * в void *.

6
ответ дан 6 December 2019 в 11:45
поделиться

Технически вы можете вызывать что угодно из C, если задано имя функции, видимое в C (прототипы и т. Д. Игнорируются на уровне ABI). Конечно, вы не можете ожидать правильных результатов, если C не может сгенерировать параметры ожидаемым образом. Как правило, очевидным решением является упрощение интерфейса до уровня C. char ** - отличный выбор для определения наибольшего общего знаменателя с вектором . Мало того, если вы знаете, что собираетесь с ним делать, вполне возможно, быстрее (и чище ИМХО).

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

extern "C" char **lots_of_strings();

Если сигнатура параметра отличается, C ++ позволит вам перегрузить функции, видимые только из C ++, и позволит им сосуществовать с Версия C:

vector<string> lots_of_strings(int);
extern "C" char **lots_of_strings();

Если вы хотите предоставить несколько способов вызова, подходящих для вызывающего языка, вы можете попробовать это (игнорируя недостатки поздней инициализации и тот факт, что bool существует в C) :

bool lots_of_strings(vector<string> &);
extern "C" int lots_of_strings(char ***);
Whatever lots_of_strings(SomeArrayType &);

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

Вы сочтете полезным скрыть измы C ++ от C, объединив #ifdef с макросом __ cplusplus .

6
ответ дан 6 December 2019 в 11:45
поделиться

См. этот FAQ . По сути, вы не можете вызывать методы C ++ (функции-члены), но вы можете вызывать автономные функции, если они объявлены с extern C. char ** - не единственная возможность, но, вероятно, самый прямолинейный. Вы можете вернуть динамически распределенный массив char * . Вам нужно будет использовать параметр out, чтобы указать длину вызывающей стороне (вы можете завершить его NULL, но это, вероятно, не идеально). Например.

char **get_string_list(size_t *len)
{
  char **array;
  size_t actual_len;
  // ...
  *len = actual_len;
  array = (char **) malloc(sizeof(char *) * actual_len);
  // ...
  return array;
}

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

5
ответ дан 6 December 2019 в 11:45
поделиться

Некоторое время назад я прочитал несколько строк об этом, и iirc вы можете использовать код / ​​структуры C ++, которые будут компилироваться на C. Но есть кое-что о статической инициализации, если я правильно понял, вы должны написать свою основную функцию на C ++ чтобы гарантировать, что это си сделано, C main не работает.

0
ответ дан 6 December 2019 в 11:45
поделиться

Если у вас есть возможность изменить код, который вы вызываете, я бы предложил изменить функцию с возврата вектора на что-то вроде:


unsigned int MyFunction(char* buff, unsigned int numLines, unsigned int stride)

Где numLines - количество выделенных строк, а stride - размер строк. Таким образом, вашей функции не нужно будет выделять память, о которой вам придется беспокоиться позже. Все это обрабатывается вызывающей стороной. Возвращаемое значение функции - количество использованных строк.

0
ответ дан 6 December 2019 в 11:45
поделиться

Если вы собираетесь предлагать одну и ту же функциональность для C и C++, я бы постарался предложить две точки входа, чтобы вы могли адаптировать одну к другой. Обратите внимание, что хотя вы можете выбрать интерфейс, который можно использовать как на C, так и на C++, в большинстве случаев интерфейс C не будет идеальным для использования на C++ (использование char** может быть хорошим решением для C, но если пользователи будут преобразовывать его обратно в типы C++ и выполнять очистку, это может загромождать код пользователя) и наоборот.

0
ответ дан 6 December 2019 в 11:45
поделиться