Таким образом, это было некоторое время, так как я использовал прямой 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
Нет, C не может использовать функции C ++, которые также недоступны в C. Однако код C может использовать код C ++ косвенно. Например, вы можете реализовать функцию C, используя C ++, и вы можете использовать непрозрачные типы в интерфейсе, чтобы подпись использовала void *
, но реализация использует класс C ++.
Эквивалент vector
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 *.
Технически вы можете вызывать что угодно из 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
.
См. этот 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;
}
Вы должны как-то освободить память. Либо укажите функцию, либо задокументируйте, как вызывающий должен это делать. Не забудьте освободить отдельные строки, если они выделяются динамически.
Некоторое время назад я прочитал несколько строк об этом, и iirc вы можете использовать код / структуры C ++, которые будут компилироваться на C. Но есть кое-что о статической инициализации, если я правильно понял, вы должны написать свою основную функцию на C ++ чтобы гарантировать, что это си сделано, C main не работает.
Если у вас есть возможность изменить код, который вы вызываете, я бы предложил изменить функцию с возврата вектора на что-то вроде:
unsigned int MyFunction(char* buff, unsigned int numLines, unsigned int stride)
Где numLines - количество выделенных строк, а stride - размер строк. Таким образом, вашей функции не нужно будет выделять память, о которой вам придется беспокоиться позже. Все это обрабатывается вызывающей стороной. Возвращаемое значение функции - количество использованных строк.
Если вы собираетесь предлагать одну и ту же функциональность для C и C++, я бы постарался предложить две точки входа, чтобы вы могли адаптировать одну к другой. Обратите внимание, что хотя вы можете выбрать интерфейс, который можно использовать как на C, так и на C++, в большинстве случаев интерфейс C не будет идеальным для использования на C++ (использование char**
может быть хорошим решением для C, но если пользователи будут преобразовывать его обратно в типы C++ и выполнять очистку, это может загромождать код пользователя) и наоборот.