Ciò è dovuto al nome mangling eseguito da C++.
extern "C" vs no extern "C"
Come esempio qui è che cosa CFF Explorer mostra per la tabella di esportazione di una dll. Il primo è stato realizzato con il compilatore C++ di Borland. Il secondo è stato realizzato con msvc.
Ordinal FunctionRVA Name RVA Name
00000001 0020E140 0032C2B6 createDevice
00000002 0020E244 0032C2C3 createDeviceEx
0000000D 00328DA4 0032C0C1 @[email protected]@IdentityMatrix
0000000E 00328DE4 0032C28A @[email protected]@IdentityMaterial
0000000C 000F9C80 001EE1B6 createDevice
0000000D 000F9CE0 001EE1C3 createDeviceEx
00000001 00207458 001EDDC7 [email protected]@[email protected]@[email protected]@A
00000002 001F55A0 001EDDF5 [email protected]@[email protected]@[email protected]@[email protected]
I primi 2 funzioni createDevice
e createDeviceEx
contengono la firma extern "C"
nel suo prototipo, mentre gli altri non lo fanno. Si noti la differenza nella codifica quando viene utilizzato il manegging C++. La differenza in realtà va a più profonda di.
ABI & normalizzazione
Come spiegato nelle altre risposte, lo standard C++ fa non specificare un UnbstractBfabbrica di alcune componentihonterface. Ciò significa che i venditori che progettano i loro strumenti possono fare praticamente tutto ciò che vogliono quando si tratta di come vengono gestite le chiamate di funzione e di come funziona il sovraccarico, purché mostri il comportamento previsto dettato dallo standard.
Con tutti questi schemi di codifica diversi, non c'è modo che un altro linguaggio possa sperare di lavorare con i moduli compilati con C++. I moduli Heck compilati con un compilatore C++ è improbabile che funzionino con un altro! I produttori di compilatori sono liberi di cambiare la codifica tra le versioni a loro discrezione.
Inoltre, nessun ABI comune significa che non esiste un modo comune di richiamare queste funzioni/metodi. Ad esempio, un compilatore potrebbe passare i suoi argomenti sullo stack mentre un altro compilatore potrebbe passarlo sul registro. Uno potrebbe passare argomenti da sinistra a destra mentre un altro potrebbe essere invertito. Se solo uno di questi aspetti non corrisponde esattamente tra il chiamante e il chiamato, la tua app si bloccherà ... cioè se sei fortunato. Invece di occuparsi di ciò, i venditori semplicemente dicono di no forzando un errore di compilazione con le diverse codifiche.
OTOH, anche se C non ha un ABI standardizzato, C è un linguaggio molto più semplice da trattare al confronto. La maggior parte dei produttori di compilatori C gestisce la decorazione delle funzioni e il meccanismo di chiamata in modo simile. Di conseguenza c'è una sorta di standard "de facto" anche se un ABI non è esplicitamente specificato nello standard. Con questa comunanza, è molto più semplice per le altre lingue interfacciare con moduli compilati con C.
Ad esempio, una decorazione della funzione __stdcall
segue una convenzione di chiamata specifica. Gli argomenti vengono spostati da destra a sinistra e il callee è responsabile della pulizia dello stack in seguito. __cdecl
è simile ma è noto che il caller è responsabile della pulizia dello stack.
La linea di fondo
Se il modulo in questione deve essere interoperabile con i linguaggi di fuori di C++, decorando in modo appropriato ed esponendo come un'API C è la soluzione migliore. Nota che stai abbandonando un po 'di flessibilità facendo questo. In particolare, non sarete in grado di sovraccaricare quelle funzioni poiché il compilatore non può più generare simboli univoci per ogni sovraccarico con manomissione del nome.
Se l'interoperabilità non è importante per il modulo in questione, verrà utilizzata solo con lo stesso strumento con cui è stata creata, quindi omettere la decorazione extern "C"
dai prototipi.
Ho aggiunto una spiegazione più dettagliata del perché ce n'è bisogno, se siete interessati. – greatwolf