Domanda

Lo so.

Chiamata funzione C da C ++:

Se la mia domanda era in C ++ e ho dovuto richiamare le funzioni da una libreria scritta in C. Poi avrei usato

//main.cpp

extern "C" void C_library_function(int x, int y);//prototype
C_library_function(2,4);// directly using it.

Questo non storpiare il nome C_library_function e linker avrebbe trovato lo stesso nome nel suo ingresso * .lib file e problema è risolto.

Chiamata funzione C ++ da C ???

Ma qui sto estendendo un'applicazione di grandi dimensioni che è scritto in C e ho bisogno di usare una libreria che è scritto in C ++. Nome pressare di C ++ sta causando problemi qui. Linker si lamenta i simboli non risolti. Beh non posso usare compilatore C ++ sopra la mia C progetto, perché questo è rottura sacco di altre cose. Qual è la via d'uscita?

Tra l'altro sto usando MSVC

È stato utile?

Soluzione

È necessario creare un'API C per esporre la funzionalità del codice C ++. In sostanza, è necessario scrivere codice C ++ che viene dichiarata extern "C" e che ha un'API C puro (se non utilizzano le classi, per esempio) che avvolge la libreria C ++. Poi si usa la libreria C pura wrapper che hai creato.

Il C API può opzionalmente seguire uno stile orientato agli oggetti, anche se C non è orientato agli oggetti. Es:

 // *.h file
 // ...
 #ifdef __cplusplus
 #define EXTERNC extern "C"
 #else
 #define EXTERNC
 #endif

 typedef void* mylibrary_mytype_t;

 EXTERNC mylibrary_mytype_t mylibrary_mytype_init();
 EXTERNC void mylibrary_mytype_destroy(mylibrary_mytype_t mytype);
 EXTERNC void mylibrary_mytype_doit(mylibrary_mytype_t self, int param);

 #undef EXTERNC
 // ...


 // *.cpp file
 mylibrary_mytype_t mylibrary_mytype_init() {
   return new MyType;
 }

 void mylibrary_mytype_destroy(mylibrary_mytype_t untyped_ptr) {
    MyType* typed_ptr = static_cast<MyType*>(untyped_ptr);
    delete typed_ptr;
 }

 void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) {
    MyType* typed_self = static_cast<MyType*>(untyped_self);
    typed_self->doIt(param);
 }

Altri suggerimenti

lo farei nel modo seguente:

(Se si lavora con MSVC, ignora i comandi di compilazione GCC)

Supponiamo che ho una classe ++ denominato AAA , definito nel file aaa.h, aaa.cpp , e che la classe AAA C ha un metodo denominato sayHi (const char * name) , che voglio consentire per il codice C.

Il codice C ++ di classe AAA - Pure C ++, io non modificarlo:

aaa.h

#ifndef AAA_H
#define AAA_H

class AAA {
    public:
        AAA();
        void sayHi(const char *name);
};

#endif

aaa.cpp

#include <iostream>

#include "aaa.h"

AAA::AAA() {
}

void AAA::sayHi(const char *name) {
    std::cout << "Hi " << name << std::endl;
}

La compilazione di questa classe come regolarmente fatto per C ++. Questo codice "non sa" che sta per essere utilizzato da codice C. Utilizzando il comando:

g++ -fpic -shared aaa.cpp -o libaaa.so

Ora, anche in C ++, creazione di un connettore C. Definire in file aaa_c_connector.h, aaa_c_connector.cpp . Questo connettore è andare a definire una funzione C, denominata AAA_sayHi (cosnt char * name) , che utilizzerà un esempio di AAA e chiamerà il suo metodo:

aaa_c_connector.h

#ifndef AAA_C_CONNECTOR_H 
#define AAA_C_CONNECTOR_H 

#ifdef __cplusplus
extern "C" {
#endif

void AAA_sayHi(const char *name);

#ifdef __cplusplus
}
#endif


#endif

aaa_c_connector.cpp

#include <cstdlib>

#include "aaa_c_connector.h"
#include "aaa.h"

#ifdef __cplusplus
extern "C" {
#endif

// Inside this "extern C" block, I can define C functions that are able to call C++ code

static AAA *AAA_instance = NULL;

void lazyAAA() {
    if (AAA_instance == NULL) {
        AAA_instance = new AAA();
    }
}

void AAA_sayHi(const char *name) {
    lazyAAA();
    AAA_instance->sayHi(name);
}

#ifdef __cplusplus
}
#endif

La compilazione è, ancora una volta, utilizzando un normale C ++ comando compilazione:

g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so

Ora ho una libreria condivisa (libaaa_c_connector.so), che implementa la funzione C AAA_sayHi (const char * name) . Ora posso creare un file principale C e compilarlo tutto insieme:

main.c

#include "aaa_c_connector.h"

int main() {
    AAA_sayHi("David");
    AAA_sayHi("James");

    return 0;
}

La compilazione utilizzando un comando C compilazione:

gcc main.c -L. -laaa_c_connector -o c_aaa

I dovrà LD_LIBRARY_PATH insieme per contenere $ PWD, e se eseguire il file eseguibile ./ c_aaa , mi metterò l'uscita mi aspetto:

Hi David
Hi James

EDIT:

In alcune distribuzioni di Linux, -laaa e -lstdc++ può essere richiesto anche per l'ultimo comando di compilazione. Grazie a @AlaaM. per l'attenzione

Supponendo che il C ++ API è C-compatibile (classi, template, ecc), si può avvolgere in extern "C" { ... }, così come avete fatto quando si va nella direzione opposta.

Se si desidera esporre oggetti e altre cose carino C ++, dovrete scrivere un wrapper API.

Si dovrà scrivere un wrapper per C in C ++, se si vuole fare questo. C ++ è compatibile, ma C non è in avanti compatibili.

Esporta le funzioni C ++ come extern "C" (aka simboli stile C), oppure utilizzare il formato di file DEF per definire i simboli di esportazione non decorati per il C ++ linker quando si crea la libreria C ++, quindi il linker C non dovrebbe avere problemi lettura

#include <iostream>

//////////////
// C++ code //
//////////////
struct A
{
  int i;
  int j;

  A() {i=1; j=2; std::cout << "class A created\n";}
  void dump() {std::cout << "class A dumped: " << i << ":" << j << std::endl;}
  ~A() {std::cout << "class A destroyed\n";}
};

extern "C" {
  // this is the C code interface to the class A
  static void *createA (void)
  {
    // create a handle to the A class
    return (void *)(new A);
  }
  static void dumpA (void *thisPtr)
  {
    // call A->dump ()
    if (thisPtr != NULL) // I'm an anal retentive programmer
    {
      A *classPtr = static_cast<A *>(thisPtr);
      classPtr->dump ();
    }
  }
  static void *deleteA (void *thisPtr)
  {
    // destroy the A class
    if (thisPtr != NULL)
    {
      delete (static_cast<A *>(thisPtr));
    }
  }
}

////////////////////////////////////
// this can be compiled as C code //
////////////////////////////////////
int main (int argc, char **argv)
{
  void *handle = createA();

  dumpA (handle);
  deleteA (handle);

  return 0;
}

È possibile anteporre la dichiarazione di funzione con la parola chiave extern “C”, per es.

extern “C” int Mycppfunction ()

{

// Codice va qui

return 0;

}

Per ulteriori esempi si può andare più in su Google su parola chiave “extern”. Hai bisogno di fare alcune cose, ma non è difficile, si otterrà un sacco di esempi da parte di Google.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top