2012-09-18 14 views
17

Dalla C++ 11 progetto, 7.5 (paragrafo 1.):La "C" esterna è di tipo separato?

Due tipi di funzione con lingua diversa legami sono tipi distinti anche se sono altrimenti identici.

così posso fare il sovraccarico sulla base di legami linguistici:

extern "C" typedef void (*c_function)(); 
typedef void (*cpp_function)(); 

void call_fun(c_function f) 
{ 
} 
void call_fun(cpp_function f) 
{ 
} 

extern "C" void my_c() 
{ 
} 
void my_cpp() 
{ 
} 
int main() 
{ 
    call_fun(my_c); 
    call_fun(my_cpp); 
} 

Ma, con GCC 4.7.1 questo codice di esempio dà i messaggi di errore:

test.cpp: In function 'void call_fun(cpp_function)': 
test.cpp:7:6: error: redefinition of 'void call_fun(cpp_function)' 
test.cpp:4:6: error: 'void call_fun(c_function)' previously defined here 

E con clangore ++:

test.cpp:7:6: error: redefinition of 'call_fun' 
void call_fun(cpp_function f) 
    ^
test.cpp:4:6: note: previous definition is here 
void call_fun(c_function f) 
    ^

Ora le domande:

  • La mia comprensione dello standard è corretta? Questo codice è valido?

  • Qualcuno sa se questi sono errori nei compilatori o se lo fanno intenzionalmente in questo modo per motivi di compatibilità?

+0

Tanto per la cronaca: lo standard C++ 03 ha esattamente la stessa frase nello stesso paragrafo, quindi questo non è una questione di una funzione di C++ 11 non ancora supportata dai compilatori. – Gorpik

+0

Vedere http://stackoverflow.com/a/10643935/1463922. Assicurarsi che le convenzioni di chiamata di C e C++ corrispondano. – PiotrNycz

risposta

8

È un bug noto in gcc e registra che non è conforme poiché questo bug blocca l'uber-bug, "problemi di conformità C++ 98".

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

Controllare la data di creazione.

C'è una discussione verso la fine, sugli aspetti pratici dell'introduzione di una correzione. Quindi la risposta alla tua ultima domanda è "entrambi": si tratta di un bug e il bug è stato lasciato intenzionalmente per compatibilità.

Altri compilatori con lo stesso problema potrebbero aver commesso l'errore in modo indipendente, ma penso che più probabilmente sanno anche che è sbagliato ma vogliono essere compatibili con bug con gcc.

+0

Triky, perché sto davvero usando i puntatori alle funzioni dei template convertite in puntatori alle funzioni "extern" C "'. Non conosco alcun modo per creare una funzione template "extern" C ", quindi penso che terrò il mio codice così com'è per ora ... – rodrigo

+0

Mmm, sembra esasperante. Immagino che tu possa farlo con (al massimo) una funzione di wrapper "extern" C "' per API C che usi, a condizione che la funzione C-linkage utilizzi un puntatore di dati utente. È possibile contraffare il puntatore della funzione C++ - linkage alla funzione C-linkage memorizzandolo nei dati dell'utente e chiamarlo da lì. "Se in dubbio aggiungi più indirezione", una specie di cosa. –

+0

@Steve_Jessop: Grazie, avevo in mente una cosa del genere, ma questo rompe il mio obiettivo di zero-overhead che ho inseguito quando usato template invece di un oggetto dispatcher con una funzione virtuale e un membro statico func ... _D'oh! _ – rodrigo

10

Il codice è chiaramente valido. G ++ (e un certo numero di altri compilatori) sono un bit lassista (per usare un eufemismo) sull'integrazione del collegamento nel tipo.

+0

+1 Sulla base del preventivo che l'OP ha fornito sembra corretto, a meno che non ci sia qualche angolo dello standard che aggiunge un'eccezione alla citata citazione. In ogni caso, conoscendo James, penso che lui conosca meglio e mi fido della sua parola su questo:) –

+1

@Als L'esempio classico in cui questo fa la differenza: passare una funzione membro statica a 'pthread_create' (o' CreateThread'). Secondo lo standard, questo è illegale (dal momento che 'pthread_create' richiede un' extern 'C "', e un membro non può essere "extern" C "'), ma sia g ++ che VC++ lo permettono. –

+0

Grazie. Il fatto è che ho un codice che si basa su questo comportamento GCC.Funziona, ovviamente, ma mi rende un po 'a disagio perché sembra totalmente non portatile. Il mio problema è se questo lassismo è intenzionale, e quindi posso considerarlo una "estensione GCC". – rodrigo

1

Per quel che vale, questo codice non riesce anche a compilare con le impostazioni predefinite in VS2012:

(8) error C2084: function 'void call_fun(c_function)' already has a body 
(4) see previous definition of 'call_fun' 
(19) error C3861: 'call_fun': identifier not found 
(20) error C3861: 'call_fun': identifier not found 
+0

Ma il compilatore online [Coumeau C++] (http://www.comeaucomputing.com/tryitout/) lo accetta senza alcun preavviso! – rodrigo