Gibt es einen Fall, in dem ein Fehlen #include
die Software zur Laufzeit beschädigen würde, während der Build noch läuft?
Mit anderen Worten, ist es möglich, dass
#include "some/code.h"
complexLogic();
cleverAlgorithms();
und
complexLogic();
cleverAlgorithms();
würden beide erfolgreich bauen, sich aber unterschiedlich verhalten?
#include
d kommt, vollständig ändern .#include <vld.h>
an einer strategischen Position in Ihrem Code platzieren. Das Entfernen oder Hinzufügen dieses VLD-Headers "bricht" das Programm nicht, beeinflusst jedoch das Laufzeitverhalten erheblich. Ich habe gesehen, wie VLD ein Programm so verlangsamt hat, dass es unbrauchbar wurde.Antworten:
Ja, das ist durchaus möglich. Ich bin mir sicher, dass es viele Möglichkeiten gibt, aber nehmen wir an, dass die Include-Datei eine globale Variablendefinition enthält, die als Konstruktor bezeichnet wird. Im ersten Fall würde der Konstruktor ausgeführt, im zweiten Fall nicht.
Das Einfügen einer globalen Variablendefinition in eine Header-Datei ist ein schlechter Stil, aber möglich.
quelle
<iostream>
in der Standardbibliothek macht genau das; Wenn eine Übersetzungseinheit enthält,<iostream>
wird dasstd::ios_base::Init
statische Objekt beim Programmstart erstellt, wobei die Zeichenströmestd::cout
usw. initialisiert werden , andernfalls nicht.Ja das ist möglich
Alles, was
#include
s betrifft, geschieht zur Kompilierungszeit. Aber Kompilierungszeiten können das Verhalten zur Laufzeit natürlich ändern:some/code.h
::dann
Mit der
#include
Überlastungsauflösung findet man das passenderfoo(int)
und druckt daher1
statt2
. DaFOO
es definiert ist, wird es zusätzlich gedrucktFOO
.Das sind nur zwei (nicht verwandte) Beispiele, die mir sofort in den Sinn kamen, und ich bin sicher, dass es noch viel mehr gibt.
quelle
Um nur auf den trivialen Fall hinzuweisen: Precompiler-Direktiven:
Und dann
Es ist vielleicht pathologisch, aber ich habe einen ähnlichen Fall erlebt:
Sieht harmlos aus. Versucht anzurufen
std::max
. Windows.h definiert jedoch max alsWenn dies
std::max
der Fall wäre, wäre dies ein normaler Funktionsaufruf, der f () einmal und g () einmal auswertet. Mit Windows.h wird f () oder g () jetzt zweimal ausgewertet: einmal während des Vergleichs und einmal, um den Rückgabewert zu erhalten. Wenn f () oder g () nicht idempotent war, kann dies zu Problemen führen. Zum Beispiel, wenn einer von ihnen ein Zähler ist, der jedes Mal eine andere Zahl zurückgibt ....quelle
using namespace std;
und verwendenstd::max(f(),g());
, wird der Compiler das Problem erkennen (mit einer undurchsichtigen Nachricht, die jedoch zumindest auf die Aufrufstelle verweist).Möglicherweise fehlt eine Vorlagenspezialisierung.
quelle
Binäre Inkompatibilität, Zugriff auf ein Mitglied oder noch schlimmer, Aufruf einer Funktion der falschen Klasse:
Eine Funktion verwendet es und es ist in Ordnung:
Eine andere Version der Klasse einbringen:
Bei Verwendung der Hauptfunktionen ändert die zweite Definition die Klassendefinition. Dies führt zu binärer Inkompatibilität und stürzt einfach zur Laufzeit ab. Beheben Sie das Problem, indem Sie das erste Include in main.cpp entfernen:
Keine der Varianten erzeugt einen Kompilierungs- oder Verbindungszeitfehler.
Die umgekehrte Situation, in der ein Include hinzugefügt wird, behebt den Absturz:
Diese Situationen sind noch viel schwieriger, wenn ein Fehler in einer alten Programmversion behoben oder eine externe Bibliothek / DLL / ein freigegebenes Objekt verwendet wird. Deshalb müssen manchmal die Regeln der binären Abwärtskompatibilität befolgt werden.
quelle
Ich möchte darauf hinweisen, dass das Problem auch in C besteht.
Sie können dem Compiler mitteilen, dass eine Funktion eine Aufrufkonvention verwendet. Wenn Sie dies nicht tun, muss der Compiler erraten, dass er den Standard verwendet, anders als in C ++, wo der Compiler die Kompilierung ablehnen kann.
Zum Beispiel,
main.c
foo.c
Unter Linux unter x86-64 ist meine Ausgabe
Wenn Sie den Prototyp hier weglassen, geht der Compiler davon aus, dass Sie ihn haben
Und die Konvention für nicht spezifizierte Argumentlisten verlangt,
float
dass konvertiert wird, um übergebendouble
zu werden. Obwohl ich gegeben habe1.0f
, konvertiert der Compiler es in1.0d
, um es an zu übergebenfoo
. Und gemäß AMD64 Architecture Processor Supplement für System V Application Binary Interfacedouble
wird das in den 64 niedrigstwertigen Bits von übergebenxmm0
. Aberfoo
erwartet einen Schwimmer, und es liest sie aus den 32 am wenigsten signifikanten Bitsxmm0
und bekommt 0.quelle