2011-10-10 12 views
13

Alcuni giorni fa, ho trovato questo pezzo di codice C++, sebbene non riesca a incollare il codice stesso, potrei ricreare il problema con qualche codice di esempio. In primo luogo, il file, namespace.h:Perché utilizzare una "C" esterna attorno a uno spazio dei nomi C++

#include <iostream> 
using namespace std; 

namespace useless{ 
    class X { 
    int m_myint; 
    static X *m_foobar; 
    X* getPrivVal(void); 
    public: 
    int getMember(void); 
    X* getStaticVal(void); 
    }; 
} 

successivo, namespace.cpp:

#include "namespace.h" 

extern "C"{ 
    namespace useless{ 
    X* X::m_foobar = NULL; 
    X* X::getPrivVal(void){ 
     if(m_foobar == NULL) 
      m_foobar = new X; 
     return(m_foobar); 
    } 
    } 
} 

namespace useless { 
    int X::getMember(void){ 
     if(m_myint == 0) 
      m_myint = 1; 
     return(m_myint); 
    } 
    X* X::getStaticVal(void){ 
     return(getPrivVal()); 
    } 
} 

using namespace useless; 

int main(void){ 
    X y; 
    cout << "The int value is " << y.getMember() << endl; 
    cout << "The value of the static member is " << y.getStaticVal() << endl; 
    return(0); 
} 

Questo codice compilato e collegato bene quando ho usato g ++ 3.4.3, ma dà il seguente errore quando uso g ++ 4.x, ho provato con GCC 4.6.1 e GCC 4.2.1. Ho provato su Linux e Mac, gli stessi risultati.

Questo è l'errore (Suse):

g++ -o namespace namespace.cpp 
namespace.h:8:15: error: previous declaration of useless::X* 
    useless::X::m_foobar with C++ linkage 
namespace.cpp:5:11: error: conflicts with new declaration with C linkage 

qualcuno può far luce su ciò che il codice legacy C++ stava cercando di fare, potrebbe questo essere un hack o soluzione alternativa per aggirare un vecchio problema di cui non sono più a conoscenza. A proposito, il metodo all'interno dello extern "C" viene chiamato dal codice C++ e non da alcun codice C come inizialmente sospettavo. FYI, questo è il codice legacy ora, potrebbe essere stato scritto nel periodo 2001/2002.


Grazie ragazzi. Sono andato avanti e mi sono liberato della "C" esterna senza alcun impatto significativo. @Bjorn Pollex: il tizio che ha scritto quel codice è sparito da tempo.

+6

Se questo codice è controllato dalla versione, controlla la cronologia per trovare chi ha scritto quello e colpiscili con un bastone finché non si pentono dei loro peccati. –

risposta

6

Sembra un tentativo di generare le variabili senza nome C++ mangling. Questa è una parte dell'uso di extern "C".

Il nuovo compilatore ovviamente si rende conto che in realtà non funziona.

2

Se si dispone di un pezzo di codice C++ che si desidera chiamare da un modulo scritto in un'altra lingua (C, FORTRAN o qualsiasi altra cosa), si desidera disattivare il nome mangling in C++.

Modifica: La cosa davvero strana è che l'hanno fatto sulla definizione ma non sulla dichiarazione. È una meraviglia che abbia mai compilato

+3

Spegnere il nome mangling non ha senso quando parli di C++ - funzioni esclusive come classi e spazi dei nomi. –

14

La direttiva extern "C" ha due effetti, disabilita il mangling quando possibile e utilizza la convenzione di chiamata C. In questo caso particolare, poiché c'è un namespace intermedio, il mangling del nome non può essere disattivato, quindi potrebbe essere stato aggiunto per forzare una particolare convenzione di chiamata.

Il codice è in realtà errato in quanto la dichiarazione non forza extern "C" ma la definizione non è corretta. Considera che se il compilatore ha appena seguito la direttiva come mostrato, il chiamante userebbe le convenzioni di denominazione e chiamata C++, mentre la funzione userebbe la variante C, se i due differiscono il risultato sarà un comportamento indefinito.

Problemi correlati