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));
}
@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
Ne pas vous devriez retourner une chaîne de caractères au lieu d'un 'std :: string'? – nouney
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