2010-03-27 20 views
5

Qual è la differenza tra le seguenti due dichiarazioni? Pensavo fossero equivalenti, ma il primo campione funziona, e il secondo no. Voglio dire compila e corre, ma il codice di visualizzazione bitmap mostra vuoto. Non l'ho ancora superato, ma mi manca qualcosa di ovvio? GUI_BITMAP è una struttura semplice che descrive una bitmap. Questo è per VC++ 2005, ma penso che fallisca anche in VC++ 2008. Graffiare la mia testa su questo ...Problema con la parola chiave extern in C++

Esempio 1:

extern "C" const GUI_BITMAP bmkeyA_cap_active; 
extern "C" const GUI_BITMAP bmkeyA_cap_inactive; 

Esempio 2:

extern "C" 
{ 
    const GUI_BITMAP bmkeyA_cap_active; 
    const GUI_BITMAP bmkeyA_cap_inactive; 
}; 

Edit: esplorare ancora di più ha dimostrato che il secondo esempio sta creando le struct, mentre il primo si riferisce a strutture esterne. Il secondo esempio non dovrebbe riuscire a collegarsi, poiché ci sono due variabili a livello globale con lo stesso nome. Ma non lo fa, invia una struttura riempita a zero al codice di visualizzazione che si arrende. Hmmm .....

Modifica 2: L'esecuzione dello stesso codice tramite un altro compilatore (IAR) non è riuscita a compilare il campione 2, con un errore relativo alla mancanza di un costruttore predefinito. Quindi immagino ci sia qualcosa di sottile nella parola chiave "extern", nelle strutture e nel C++ che non ottengo. Se le cose nella zona esterna fossero funzioni, i due campioni sarebbero identici, giusto?

risposta

3

Il linker può risolvere in silenzio i simboli duplicati dietro la schiena. È possibile ottenere librerie statiche da un fornitore e collegarle al proprio programma. Qual è la soluzione per la situazione in cui si hanno due librerie del genere e entrambi definiscono un simbolo comune? Il linker risolverà solo questo, scegliendo l'una o l'altra definizione, e lasciandoti ad affrontare il fallout. Come stai gestendo la fase di collegamento della tua applicazione? Potresti avere risultati migliori se colleghi direttamente i file .o invece di metterli in librerie intermedie prima di collegare l'applicazione finale.

This page della documentazione ARM descrive bene il problema - mi aspetto un comportamento simile sta accadendo nel vostro caso:

definizioni multiple di un simbolo in diversi oggetti della biblioteca non sono necessariamente rilevato. Una volta che il linker ha trovato una definizione adatta per un simbolo, smette di cercarne altri. Supponendo che l'oggetto contenente il simbolo duplicato non venga caricato per altri motivi, non si verificherà alcun errore. Questo è intenzionale e particolarmente utile in alcune situazioni.

Edit: Più ricerca ha alzato che questo problema è causato a causa di una violazione della "One Definition Rule", e di conseguenza il compilatore/linker non sono tenuti ad informare l'utente del problema. Questo rende la tua domanda un duplicato di this one.

+0

Grazie per la risposta, ma non ci sono oggetti libreria in uso qui, questo è tutto solo il mio codice, una miscela di C e C++. La mia domanda originale rimane: qual è la differenza tra Campione 1 e Campione 2 - Ho pensato che dovrebbero generare esattamente lo stesso codice? Se le cose fossero funzioni anziché strutture: sono la stessa cosa, giusto? – Jeff

+1

@Jeff, la rapida risposta alla tua domanda è che no, quei due non sono la stessa cosa, ecco perché vedi problemi.Nel secondo caso, stai solo modificando le istruzioni all'interno di '{}' per usare le convenzioni di link di C. Nel primo esempio, stai facendo quello * plus * che indica che le variabili sono dichiarate altrove. http://msdn.microsoft.com/en-us/library/0603949d(VS.80).aspx –

0

Il secondo esempio potrebbe essere equivalente al primo con un extern aggiuntivo di fronte al const. Nel primo caso, il compilatore probabilmente combina i due usi di extern. Nel secondo caso, suppongo che il compilatore non esegua la virgola di tutto nello spazio esterno extern per qualsiasi motivo.