2010-05-09 5 views
18

Forse non sono la comprensione delle differenze tra C e C++, ma quando e perché abbiamo bisogno di usareQuando utilizzare extern "C" in parole semplici?

extern "C" { 

? Apparentemente è una "convenzione di linkage".

Ho letto brevemente e ho notato che tutti i file di intestazione .h inclusi in MSVS circondano il loro codice con esso. Che tipo di codice è esattamente "codice C" e NON "codice C++"? Pensavo che il C++ includesse tutto il codice C?

Suppongo che questo non sia il caso e che C++ sia diverso e che le funzioni/funzioni standard esistano nell'uno o nell'altro ma non entrambi (ad esempio: printf è C e cout è C++), ma che C++ è compatibile all'indietro anche se la dichiarazione "C" extern. È corretto?

La mia prossima domanda dipende dalla risposta al primo, ma lo chiederò comunque qui: Poiché i file di intestazione MSVS che sono scritti in C sono circondati da extern "C" {...}, quando mai devi usarlo tu stesso nel tuo codice? Se il tuo codice è C e stai provando a compilarlo in un compilatore C++, non dovrebbe funzionare senza problemi perché tutti i file h standard che includi avranno già la cosa "C" extern con il compilatore C++?

Devi utilizzare questo quando si compila in C++ ma si collega a librerie C già create o qualcosa del genere?

+6

C++ NON è un superset di C. Esiste una C valida che non è C++ valida. –

+1

@ Theatrus-- questo tipo di affermazione richiede un esempio. – mmr

+0

theatrus: Ma anche quello non è sempre il caso? – Russel

risposta

0

Le funzioni C++ sono soggette a name mangling. Ciò rende impossibile chiamare direttamente dal codice C a meno che non venga utilizzato extern "C".

9

I compilatori C++ manipolano i nomi nella tabella dei simboli in modo diverso rispetto ai compilatori C. È necessario utilizzare la dichiarazione extern "C" per comunicare al compilatore C++ di utilizzare invece la convenzione di maneggevolezza C durante la creazione della tabella dei simboli.

+0

La risposta è breve e corretta. –

21

è necessario utilizzare extern "C" in C++ quando si dichiara una funzione che è stata implementata/compilato in C. L'uso del extern "C" dice al compilatore/linker di utilizzare la denominazione C e convenzioni di chiamata, invece del ++ nome mangling C e C++ chiamando convenzioni che sarebbero usate diversamente. Per le funzioni fornite da altre librerie, non sarà quasi mai necessario utilizzare extern "C", poiché le librerie ben scritte avranno già questo contenuto per le API pubbliche che esporta in C e C++. Se, tuttavia, scrivi una libreria che vuoi rendere disponibile sia in C che in C++, dovrai metterla condizionatamente nelle intestazioni.

Per quanto riguarda se tutto il codice C è codice C++ ... no, non è corretto. È un mito popolare che C++ sia un "superset di C". Mentre C++ si sforza certamente di essere il più compatibile possibile con C, ci sono alcuni incompatibilities. Ad esempio, bool è C++ valido ma C non valido, mentre _Bool esiste in C99, ma non è disponibile in C++.

Per quanto riguarda la necessità di utilizzare la "C" di extern con i file ".h" del sistema ... qualsiasi implementazione ben progettata avrà quelle in uso per voi, in modo da non dover utilizzare loro. Tuttavia, per essere certi che vengano forniti, è necessario includere il file di intestazione equivalente che inizia con "c" e omette ".h". Ad esempio, se si include <ctype.h>, quasi tutti i sistemi ragionevoli avranno aggiunto la "C" esterna; tuttavia, per essere certi di un'intestazione compatibile con C++, dovresti invece includere l'intestazione <cctype>.

Potresti essere interessato anche a Mixing C and C++ from the C++ FAQ Lite.

+0

Grazie per tutte le risposte. Quindi devo solo usarlo quando includo il codice che è già stato compilato in un compilatore C? – Russel

+0

@Russel, si, supponendo che lo si includa da C++ e presupponendo che l'intestazione non usi già "C" extern. –

+0

Penso che sia una bella risposta! –

2

Uso 'extern c' in modo che C# possa leggere il mio codice C++ senza dover calcolare il nome di mangling extra durante l'esportazione di una funzione di dll C++. Altrimenti, ci sono caratteri extra privi di senso (o veramente, non inglesi) che devo aggiungere alla fine di un punto di ingresso di una funzione sul lato C# per poter accedere correttamente a una funzione C++ in una DLL.

2

extern "C" {} i blocchi indicano a un compilatore C++ di utilizzare le convenzioni di denominazione e chiamata C. Se non lo usi, riceverai errori di linker se tenti di includere una libreria C con il tuo progetto C++ perché C++ mangerà i nomi. Io tendo ad usare questo su tutte le mie intestazioni C solo nel caso in cui siano mai utilizzati in un progetto C++:

#ifdef __cplusplus 
extern "C" { 
#endif 

/* My library header */ 

#ifdef __cplusplus 
} // extern 
#endif 
2

È necessario utilizzare extern "C" quando si desidera utilizzare la convenzione di chiamata C in codice compilato da un compilatore C++ . Ci sono due ragioni:

  • Hai una funzione implementata in C e vuoi chiamarla da C++.

  • Si dispone di una funzione implementata in C++ e si desidera richiamarla da C. Si noti che in questo caso è possibile utilizzare solo la parte C di C++ nell'interfaccia della funzione (nessuna classe, ...).

parte C Questo vale anche quando si desidera interoperare tra C++ e altri linguaggi che utilizzano la stessa vocazione e le convenzioni di denominazione come C.

Tipicamente le dichiarazioni in un file di intestazione C sono circondati con

#ifdef __cplusplus 
extern "C" { 
#endif 

[... C declarations ...] 

#ifdef __cplusplus 
} 
#endif 

per renderlo utilizzabile da C++.

16

Le altre risposte sono corrette, ma un esempio di "boilerplate" completo probabilmente aiuterà. Il metodo canonico per incluso il codice C in C e/o progetti di C++ è la seguente:

// 
// C_library.h 
// 

#ifdef __cplusplus 
extern "C" { 
#endif 

// 
// ... prototypes for C_library go here ... 
// 

#ifdef __cplusplus 
} 
#endif 

-

// 
// C_library.c 
// 

#include "C_library.h" 

// 
// ... implementations for C_library go here ... 
// 

-

// 
// C++_code.cpp 
// 

#include "C_library.h" 
#include "C++_code.h" 

// 
// ... C++_code implementation here may call C functions in C_library.c ... 
// 

Nota: quanto sopra vale anche per chiamare C codice da Objective-C++.

+0

Ottimo esempio, grazie. Ho letto sulla chiamata di convenzioni per C++ .. (_cdecl, _stdcall, _fastcall, ecc.). C'è solo una convenzione di chiamata per C ?? – Russel

+0

@Russel: _cdecl, _stdcall, _fastcall, ecc. Sono tutti abomini non specifici di Windows che non si trovano nel mondo civilizzato. ;-) –

+0

Mi scuso :) Qualcuno potrebbe indicarmi una documentazione migliore sulle convenzioni di chiamata rispetto a MSDN? Inoltre, C ha solo una convenzione di chiamata standard? – Russel