2012-04-04 15 views
2

Dies ist etwas, das ich einfach blind akzeptiert und als "so wie es ist" gefolgt ist. Ich versuche, das dahinter liegende "Warum" tiefer zu verstehen.Auf der Suche nach einem tieferen Verständnis von Visual Studio C-Laufzeitbibliothek Link-Verhalten

  • statische Bibliothek Liba - utulizes einige C-Laufzeit ruft
  • statische Bibliothek libb - nutzt einige C-Laufzeit
  • ausführbare App nennt - nutzt Liba, libb, und einige C-Laufzeit ruft

Es ist ziemlich gut dokumentiert here und eine Reihe von anderen Orten, die alle Module an einen bestimmten Aufruf des Linkers übergeben wurden mit der gleichen Laufzeitbibliothek Compiler-Option kompiliert worden sein müssen.

Wenn die gesamte Symbolauflösung während des letzten Links für die App ausgeführt wird, wie in den Abschnitten here und here beschrieben, warum ist das der Fall? Warum müssen LibA und LibB sogar eine bestimmte Laufzeitbibliothek angeben, die beim Erstellen verwendet wird? Sollte die C-Laufzeit nicht aufrufen, verwenden sie nur die Auflösung für die Laufzeit, die App für den Link angibt.

Ist dies ein Problem in anderen C-Entwicklungsumgebungen oder ist es spezifisch für Visual Studio?

+2

Die CRT ist einfach nicht sehr kompatibel mit dem Begriff der Module, hat es eine Menge von globalem Zustand. Eine Variable wie errno ist ein gutes Beispiel. Um die Freigabe dieses Status zwischen EXE und DLLs zu ermöglichen, muss die Definition von errno gehackt werden, um zu einem Funktionsaufruf zu werden, so dass der einzige und gemeinsam genutzte Wert erhalten werden kann. Ausgelöst von/MD. Der Versuch, eine OBJ, die auf Fehlern verweist, mit einer anderen zu verknüpfen, die sich auf _errno() bezieht, kann nicht funktionieren.Nicht ganz genau, aber repräsentativ für das Problem. –

Antwort

0

Wie Hans Passant in seinem Kommentar erwähnt hat, gibt es einige globale Statuselemente, die zwischen einer DLLs-Laufzeit und einer statischen Link-Laufzeit wechseln müssen. Noch schlimmer als sein Beispiel ist, wenn sich die Größe eines Typs ändert, je nachdem, welche Laufzeit er erstellt hat. Allerdings gibt es noch ein paar Gründe:

Debug vs Release:
Die Debug-Runtimes wird rund um dynamisch zugewiesenen Speicher guard Bytes legen. Dies ermöglicht ihre Speicherzuweisung und das Freigeben von Code, um zusätzliche Überprüfungen durchzuführen, die Ihnen helfen, Speicherprobleme wie Double-Frees und Schreiben außerhalb der zugewiesenen Puffer zu finden. Die Release-Laufzeiten nutzen die zusätzlichen Checks nicht zugunsten der Optimierung. Wenn Speicher mit einem zugewiesen und mit einem anderen freigegeben wird, erhalten Sie daher möglicherweise unvorhersehbare Ergebnisse.

DLL vs statische Bindung:
In Windows ist die Faustregel, dass Sie Speicher in dem gleichen Modul befreien müssen, die Sie zugeordnet. Mit anderen Worten, wenn Sie Speicher in msvcrt.dll zugewiesen haben, müssen Sie es auch dort freigeben. Wenn daher einige Teile einer Anwendung mit einer statischen Laufzeitumgebung und einer Verbindung mit einer Laufzeit-DLL verknüpft sind, kann diese Regel verletzt werden. Wenn dies geschieht, können Sie auch unvorhersehbare Ergebnisse einschließlich Ausnahmen erhalten.

Multithreading vs Singlethread:
Das Potenzial für Konflikte zwischen diesen zwei Laufzeittypen sollte klar sein. Die Singlethread-Version ist nicht threadsicher, so dass das Mischen mit etwas, das Threadsicherheit erwartet, später zu einem interessanten Debugging führt. Diese Unterscheidung ist größtenteils nur in den älteren MS-Compilern vorhanden, da die einzige Option in neueren Releases Multithread ist.

Siehe auch diese ähnliche Frage: Mixing Static Libraries of C Code built from different versions of Visual Studio 2002 and later