5 Stimmen

Problem mit dem extern-Schlüsselwort in C++

Was ist der Unterschied zwischen den folgenden beiden Deklarationen? Ich dachte, sie wären äquivalent, aber das erste Beispiel funktioniert, und das zweite nicht. Es kompiliert und läuft, aber der Code zur Anzeige des Bitmaps zeigt leer. Ich habe es noch nicht durchgesehen, aber fehlt mir etwas Offensichtliches? GUI_BITMAP ist eine einfache Struktur, die ein Bitmap beschreibt. Dies ist für VC++ 2005, aber ich glaube, es funktioniert auch nicht in VC++ 2008. Dieser Fall lässt mich wirklich nachdenklich werden...

Beispiel 1:

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

Beispiel 2:

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

Bearbeiten: Weitere Untersuchungen haben gezeigt, dass das zweite Beispiel die Strukturen erstellt, während das erste auf externe Strukturen verweist. Das zweite Beispiel sollte eigentlich fehlschlagen, da es zwei Variablen im globalen Bereich mit demselben Namen gibt. Aber das tut es nicht, es sendet eine mit Nullen gefüllte Struktur an den Anzeigecode, der dann aufgibt. Hmmm.....

Bearbeiten 2: Wenn ich denselben Code durch einen anderen Compiler laufen lasse (IAR), scheitert das Kompilieren des Beispiels 2 tatsächlich mit einem Fehler bezüglich eines fehlenden Standardkonstruktors. Also vermute ich, dass es etwas Subtiles am "extern" Schlüsselwort, an den Strukturen und an C++ gibt, das ich nicht verstehe. Wenn die Dinge im externen Bereich Funktionen wären, wären die beiden Beispiele identisch, stimmt's?

3voto

Carl Norum Punkte 210051

Ihr Linker löst möglicherweise stillschweigend die doppelten Symbole im Hintergrund auf. Sie könnten statische Bibliotheken von einem Anbieter erhalten und diese mit Ihrem Programm verknüpfen müssen - was ist die Lösung für die Situation, in der Sie zwei solche Bibliotheken haben und sie beide ein gemeinsames Symbol definieren? Der Linker löst das einfach auf, wählt eine oder die andere Definition aus und lässt Sie mit den Folgen umgehen. Wie gehen Sie mit dem Verlinkungsprozess Ihrer Anwendung um? Sie könnten bessere Ergebnisse erzielen, wenn Sie .o-Dateien direkt verknüpfen, anstatt sie in Zwischenbibliotheken zu platzieren, bevor Sie die endgültige Anwendung verknüpfen.

Diese Seite der ARM-Dokumentation beschreibt das Problem gut - ich gehe davon aus, dass ein ähnliches Verhalten in Ihrem Fall auftritt:

Mehrere Definitionen eines Symbols in verschiedenen Bibliotheksobjekten werden nicht unbedingt erkannt. Sobald der Linker eine geeignete Definition für ein Symbol gefunden hat, hört er auf, nach anderen zu suchen. Vorausgesetzt, das Objekt, das das doppelte Symbol enthält, wird aus anderen Gründen nicht geladen, tritt kein Fehler auf. Dies ist beabsichtigt und in einigen Situationen besonders nützlich.

Bearbeitung: Weitere Recherchen haben ergeben, dass dieses Problem durch einen Verstoß gegen die "One Definition Rule" verursacht wird und der Compiler/Linker daher nicht verpflichtet sind, Sie über das Problem zu informieren. Das macht Ihre Frage zu einer Duplikat von dieser.

0voto

MSN Punkte 51308

Das zweite Beispiel könnte dem ersten entsprechen, nur mit einem zusätzlichen "extern" vor dem "const". Im ersten Fall kombiniert der Compiler wahrscheinlich die beiden Verwendungen von "extern". Im zweiten Fall würde ich annehmen, dass der Compiler aus irgendeinem Grund nicht alles im Bereich von "extern" als "extern" kennzeichnet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X