2013-07-19 1 views
1

Je l'ai regardé here et here et à quelques autres liens mentionnés dans la première question et je le code suivant déjà:fonction d'appel C++ à partir d'un code C

Le fichier .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; 
} 

le fichier en-tête/éditeur de liens:

#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 

Ma question est ce qui se passe dans le peu au-dessus que je ne suis pas sûr de quoi se taper. Je suis en train d'appeler la fonction dans le fichier .cpp de mon C fonction principale int main(int argc, char** argv) {}

+0

@MarkGarcia ont réédité la question et titre à ce sujet voir surtout la fin de la question ... c 'principale int main (int argc, char ** argv) {}' – cxzp

+1

Ne pas vous devriez retourner une chaîne de caractères au lieu d'un 'std :: string'? – nouney

+0

Vous ne pouvez pas. Le type de résultat d'exec n'existe pas en C, vous devrez peut-être écrire un wrapper compatible c dans la partie C++. – urzeit

Répondre

3

Vous devez déclarer la fonction comme extern « C » dans le fichier cpp:

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

Dans l'en-tête/éditeur de liens le fichier que vous devez déclarer est un prototype avec le mot-clé « extern », comme ceci:

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

aussi, êtes-vous sûr de vouloir revenir un C++ de std :: string à votre code C?

+0

bien je veux la sortie de la commande "arp -a" que je suis obtenu en utilisant la fonction cplusplus _popen - je reçois une erreur sur les types de retour en raison de la std :: String que suggérez-vous? – cxzp

+0

J'ai modifié ma réponse. Pour retourner une chaîne de style C au lieu de std :: string, faites simplement 'return myString.c_str();'. – Kelm

+2

qui va se casser horriblement. cela retournera un pointeur vers une variable locale –

4

Pour appeler des fonctions C++ à partir de C, vous devez effectuer deux opérations. 1) Laisser le code C++ savoir qu'il va être utilisé par C afin qu'il puisse générer des symboles C-friendly. 2) Cacher toute fonctionnalité que C ne peut pas comprendre. La première partie est facilement réalisée en définissant simplement les fonctions comme vous le feriez en C (I.E. n'utilisez pas de fonctionnalités C++ uniquement comme namespaces) et en les enveloppant dans un bloc externe "C" si C++ est défini. Vous voulez essentiellement que votre fichier d'en-tête contienne du code C uniquement, puis ouvrez simplement le bloc externe en haut et fermez-le au bas du fichier (mon exemple le rendra plus clair).

La deuxième partie est un peu plus compliquée, mais pas trop difficile. Dans votre cas, votre fonction renvoie une chaîne std :: string qui est une classe C++ uniquement. Il ne peut pas être utilisé en C et doit donc être remplacé par quelque chose qui peut être utilisé en C, ou doit être caché derrière quelque chose que C peut utiliser. Par souci d'argument, supposons que vous ne pouvez pas remplacer std :: string par say, char *. Dans ce cas, vous devez masquer std :: string du code C-face. Le moyen commun de faire cela est d'utiliser un opaque pointer. Fondamentalement, le code C-face ne traite que d'un pointeur vers quelque chose. Ce quelque chose dont il ne sait rien, ni ne s'en soucie. Le code C++ est libre d'utiliser un std :: string en interne, mais il doit s'assurer de le cacher avant de s'interfacer avec l'API C. Dans mon exemple, vous pouvez voir que j'ai fourni un pointeur opaque à une structure que j'ai appelée cppstring.

Dans le fichier source, cppstring est juste une structure qui contient une chaîne std :: string. J'ai modifié votre code d'exemple pour utiliser la nouvelle structure cppstring. Une chose importante à noter est que parce que le code C ne peut traiter qu'avec un pointeur sur une chaîne de caractères, nous devons le créer sur le tas dans notre code C++ et lui renvoyer le pointeur. Cela signifie que nous devons fournir aux utilisateurs C un moyen de les libérer lorsqu'ils sont terminés, ce que j'ai également fourni dans l'exemple. En utilisant cette technique, vous pouvez placer l'intégralité de std :: string derrière une API C, ce qui permet aux utilisateurs C d'utiliser toutes les fonctionnalités fournies par std :: string. J'ai fourni un exemple d'encapsulation de std :: string :: substr pour vous montrer comment.

N.B. Je n'ai pas compilé ni testé ce code et pour des raisons de simplicité, je n'ai inclus aucun des fichiers d'en-tête pertinents, etc.Néanmoins, cela devrait suffire pour vous aider à démarrer.

// 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)); 
}