2013-07-19 3 views
1

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

.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) {}

+0

@MarkGarcia повторно редактировал вопрос & название по этому вопросу см в основном конец вопроса ... й основной 'Int основной (INT ARGC, символ ** ARGV) {}' – cxzp

+1

Разве вы не должны верните C-строку вместо 'std :: string'? – nouney

+0

Вы не можете. Тип результата exec не существует на C, вам, возможно, потребуется написать c-совместимую обертку в C++-части. – urzeit

ответ

3

Вы должны объявить функцию как экстерн «C» в файле CPP:

extern "C" char *exec(char* cmd, FILE* pipe) { 
    ... 
} 

в заголовке/линкере файл вам нужно объявить это прототип с ключевым словом «Экстерн», например, так:

extern char *exec(char* cmd, FILE* pipe); 

Кроме того, вы уверены, что хотите вернуть с ++ зЬй :: строку кода C?

+0

ну, я хочу получить команду «arp -a», которую я получаю с помощью функции cplusplus _popen - я получаю ошибку на типах возврата из-за std :: String, что бы вы предложили? – cxzp

+0

Я изменил свой ответ. Чтобы вернуть строку стиля C вместо std :: string, просто выполните 'return myString.c_str();'. – Kelm

+2

, который сломается ужасно. он вернет указатель на локальную переменную –

4

Чтобы вызвать функции C++ из C, вам нужно сделать две вещи. 1) Пусть код C++ знает, что он будет использоваться C, чтобы он мог генерировать C-дружественные символы. 2) Скрыть любую функциональность, которую C не может понять.

Первая часть легко достигается путем простого определения функций, как в C (I.E. не использовать какие-либо объекты на C++, такие как пространства имен), а затем их обертывание в блок extern «C», если определено C++. В основном вы хотите, чтобы ваш заголовочный файл содержал только C-код, а затем просто откройте блок extern вверху и закройте его в нижней части файла (мой пример сделает это более понятным).

Вторая часть немного сложнее, но не слишком сложна. В вашем случае ваша функция возвращает std :: string, которая является классом C++. Он не может использоваться в C и поэтому либо должен быть заменен чем-то, что можно использовать в C, либо его нужно скрывать за тем, что C может использовать. Для аргумента предположим, что вы не можете заменить std :: string на say, char *. В этом случае вам нужно скрыть std :: string из кода C-обрамления. Обычный способ сделать это - использовать opaque pointer.

В принципе, код C-обрамления имеет только указатель на что-то. Это то, о чем он не знает и не заботится. Код C++ может свободно использовать std :: string внутри, но должен обязательно скрыть его перед взаимодействием с C API. В моем примере вы можете видеть, что я предоставил непрозрачный указатель на структуру, которую я назвал cppstring.

В исходном файле cppstring - это просто структура, содержащая std :: string. Я изменил ваш примерный код, чтобы использовать новую структуру cppstring. Важно отметить, что, поскольку код C может обрабатывать только указатель на cppstring, нам нужно создать его в куче в нашем C++-коде и вернуть указатель на него. Это означает, что мы должны предоставить пользователям C некоторый способ освободить его, когда они будут сделаны, что я также представил в примере.

Используя эту технику, вы можете обернуть всю std :: string за API C, чтобы пользователи C могли использовать все функции, которые предоставляет std :: string. Я привел пример wrapping std :: string :: substr, чтобы показать вам, как это сделать.

N.B. Я не компилировал и не тестировал этот код, и для простоты я не включил ни один из соответствующих файлов заголовков и т. Д.Тем не менее, этого должно быть достаточно, чтобы вы начали.

// 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)); 
} 
Смежные вопросы