Так я посмотрел Вот а также Вот и по нескольким другим ссылкам, упомянутым в первом вопросе, и у меня уже есть следующий код:
Файл .cpp:
#include "arp_piping.h"
#include <string>
#include <iostream>
#include <stdio.h>
std::string exec(char* cmd, FILE* pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
_pclose(pipe);
return result;
}
Файл заголовка / компоновщика:
#ifndef ARP_PIPING_H
#define ARP_PIPING_H
#endif
#ifdef __cplusplus
#define EXTERNC extern "C"#else
#define EXTERNC
#endif
my function goes here something like
EXTERNC .....exec(char* cmd, FILE* pipe) ????
#undef EXTERNC
Мой вопрос заключается в том, что написано выше, поскольку я не уверен, что печатать. Я пытаюсь вызвать функцию в файле .cpp из моей главной функции C int main(int argc, char** argv) {}
Вам нужно объявить функцию как extern «C» в файле cpp:
extern "C" char *exec(char* cmd, FILE* pipe) {
...
}
В файле header / linker вам нужно объявить его прототип с ключевым словом «extern», вот так:
extern char *exec(char* cmd, FILE* pipe);
Кроме того, вы уверены, что хотите вернуть std :: string c ++ в ваш код C?
Для вызова функций C ++ из C вам нужно сделать две вещи. 1) Пусть код C ++ знает, что он будет использоваться C, чтобы он мог генерировать символы, дружественные к C. 2) Скрыть любую функциональность, которую C не может понять.
Первая часть легко достигается путем простого определения функций, как в C (т. Е. Не используйте никаких функций C ++, таких как пространства имен), а затем оборачивая их во внешний блок «C», если определен C ++. По сути, вы хотите, чтобы ваш заголовочный файл содержал код только для C, а затем просто откройте блок extern вверху и закройте его внизу файла (мой пример прояснит это).
Вторая часть немного сложнее, но не слишком сложна. В вашем случае ваша функция возвращает std :: string, который является классом только для C ++. Он не может быть использован в C и, следовательно, либо должен быть заменен чем-то, что можно использовать в C, либо он должен быть скрыт за тем, что может использовать C. Ради аргумента давайте предположим, что вы не можете заменить std :: string на скажем, char *. В этом случае вам нужно скрыть std :: string из кода, обращенного к Си. Обычный способ сделать это — использовать непрозрачный указатель.
По сути, C-ориентированный код имеет дело только с указателем на что-то. Это то, о чем он не знает и не заботится. Код C ++ может использовать внутренне std :: string, но должен обязательно скрыть его, прежде чем взаимодействовать с C API. В моем примере вы можете видеть, что я предоставил непрозрачный указатель на структуру, которую я назвал cppstring.
В исходном файле cppstring — это просто структура, которая содержит std :: string. Я изменил ваш пример кода, чтобы использовать новую структуру cppstring. Важно отметить, что, поскольку код C может иметь дело только с указателем на строку cppstring, нам нужно создать его в куче нашего кода C ++ и вернуть указатель на него. Это означает, что мы должны предоставить пользователям C некоторый способ освободить его, когда они закончат, что я также предоставил в примере.
Используя эту технику, вы можете обернуть весь std :: string за C API, что позволяет пользователям C использовать все функции, которые предоставляет std :: string. Я представил пример обтекания std :: string :: substr, чтобы показать вам, как это сделать.
Нотабене Я не компилировал и не тестировал этот код, и для простоты я не включил ни одного из соответствующих заголовочных файлов и т. Д. Тем не менее, этого должно быть достаточно, чтобы вы начали.
// C header
#ifdef __cplusplus
extern "C" {
#endif
typedef struct cppstring *cppstring_p;
cppstring_p exec(char *cmd, FILE *pipe);
void free_cppstring(cppstring_p cppstr);
/* example of wrapping std::string::substr for C users */
cppstring_p substr(cppstring_p str, int pos, int count);
#ifdef __cplusplus
}
#endif// CPP source
struct cppstring {
std::string data;
cppstring(void) {}
cppstring(std::string const& s) : data(s) {}
};cppstring_p exec(char *cmd, FILE *pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
auto result = new cppstring;
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result->data += buffer;
}
_pclose(pipe);
return result;
}void free_cppstring(cppstring_p cppstr) {
delete cppstr;
cppstr = nullptr;
}cppstring_p substr(cppstring_p str, int pos, int count) {
assert(str);
return new cppstring(str->data.substr(pos, count));
}