wake-up-neo.com

Sind Inline-Variablen über Grenzen hinweg eindeutig?

Dies ist eine Nachbearbeitung von dieser Frage .
Wie in den Kommentaren zur Antwort erwähnt:

Eine Inline-Variable hat die Eigenschaft, dass - in jeder Übersetzungseinheit dieselbe Adresse hat. [...] Normalerweise haben Sie dies durch die Definition der Variablen in einer cpp-Datei erreicht. Mit dem Inline-Bezeichner können Sie Ihre Variablen jedoch nur in einer Header-Datei deklarieren/definieren, und jede Übersetzungseinheit, die diese Inline-Variable verwendet, verwendet genau dasselbe Objekt.

Darüber hinaus aus der Antwort selbst:

Obwohl die Sprache nicht garantiert (oder gar nicht erwähnt) wird, was passiert, wenn Sie diese neue Funktion über die Grenzen gemeinsamer Bibliotheken hinweg verwenden, funktioniert sie auf meinem Computer.

Mit anderen Worten, es ist nicht klar, ob garantiert wird, dass eine Inline-Variable über die Grenzen hinweg eindeutig ist, wenn Shared Libraries beteiligt sind. Jemand hat empirisch bewiesen, dass es auf einigen Plattformen funktioniert, aber es ist keine richtige Antwort und könnte auf anderen Plattformen alles kaputt machen.

Gibt es eine Garantie hinsichtlich der Eindeutigkeit einer Inline-Variablen, wenn sie grenzüberschreitend verwendet wird, oder handelt es sich lediglich um ein Implementierungsdetail, auf das ich mich nicht verlassen sollte?

17
skypjack

So interpretiere ich den Standard. Gemäß basic.link/1 :

Ein Programm besteht aus einer oder mehreren Übersetzungseinheiten, die miteinander verbunden sind.

Es sagt nichts über statisches Linking oder dynamisches Linking aus. Ein Programm besteht aus Übersetzungseinheiten, die miteinander verbunden sind. Es spielt keine Rolle, ob die Verknüpfung in zwei Schritten erfolgt (erstellen Sie zuerst eine .dll/.so, und dann verknüpft der dynamische linker alle dynamischen libs + ausführbaren Dateien).

In meiner Interpretation ist es also egal, ob ein Programm dynamisch oder statisch verknüpft ist, die Implementierung sollte sich gleich verhalten: Eine statische Klasse-Variable sollte eindeutig sein (unabhängig davon, ob sie inline ist oder nicht).

Unter Linux trifft dies zu.

Unter Windows funktioniert dies nicht unter allen Umständen. Daher verstößt es in meiner Interpretation gegen den Standard unter diesen Umständen (wenn Sie eine separate DLL erstellen, die die statische Nicht-Inline-Variable und alle anderen DLL-Dateien und die exe bezieht sich auf diese Variable, es funktioniert.

8
geza

C++ hat derzeit kein Konzept für gemeinsam genutzte Bibliotheken. Die Art und Weise, wie sich inline in gemeinsam genutzten Bibliotheken verhält, wäre implementierungs- und plattformspezifisch.

Die Tatsache, dass [basic.link]/1 besagt, dass "A-Programm aus einer oder mehreren Übersetzungseinheiten besteht." Bedeutet nicht ganz, dass ein Programm mit einem anderen, bereits verknüpften Modul verknüpft ist sollte sich gleich verhalten.

Im Laufe der Jahre wurden zahlreiche Vorschläge zur Bereinigung der Situation vorgelegt ( N1400 , N1418 , N1496 , N1976 , N2407 , N3347 , N4028 ), von denen keiner den Boden abbekam. Eine generische Implementierung ist nur schwer und C++ versucht im Allgemeinen, die Implementierungsdetails zu meiden. Wie GCC formuliert es :

Bei Zielen, die weder COMDAT noch schwache Symbole unterstützen, werden die meisten Entitäten mit unbestimmter Verknüpfung als lokale Symbole ausgegeben, um doppelte Definitionsfehler des Linkers zu vermeiden. Für die lokale Statik in Inlines ist dies nicht der Fall, da mehrere Kopien mit Sicherheit fast alles kaputt machen.

MSVC macht standardmäßig keine Symbole verfügbar. Jedes "externe" Symbol muss explizit mit einer plattformspezifischen __declspec(dllexport)..__ deklariert werden. Daher kann nicht behauptet werden, dass Windows mit C++ inkompatibel ist. Keine der C++ - Regeln wird hier verletzt, weil es keine gibt.

4
rustyx

Gibt es eine Garantie hinsichtlich der Eindeutigkeit einer Inline-Variablen, wenn sie grenzüberschreitend verwendet wird, oder handelt es sich lediglich um ein Implementierungsdetail, auf das ich mich nicht verlassen sollte?

Es liegt an Ihnen, dies sicherzustellen (indem Sie sicherstellen, dass alle Deklarationen tatsächlich gleich sind).

Der Compiler kann dies offensichtlich nicht überprüfen und der Linker stört das nicht. Wenn Sie also den Linker anlügen (durch nicht, so), werden Sie in Schwierigkeiten geraten.


OK, da nicht jeder das bekommt, was ich unter "Lüge den Linker" verstehe, werde ich es ein bisschen ausarbeiten.

@oliv freundlicherweise zur Verfügung gestellt diesen Link , der unter anderem Folgendes sagt (Kommentar meines):

Duplizierte Kopien dieser Konstrukte [d.h. Variablen, die in mehreren TUs inline deklariert werden] werden zur Verbindungszeit verworfen.

Was gut ist, das brauchen wir. Die Sache ist, Sie wissen nicht, welche) (offensichtlich wird nur eine beibehalten, also wissen Sie nicht, welche der beiden sein wird).

Also, wenn sie sich unterscheiden, wissen Sie nicht, mit welcher Sie am Ende landen werden, und was Sie damit enden, ist (eine besonders schleichende Form von UB). Das meinte ich mit "Lüge den Linker". Durch die unterschiedliche Deklaration Ihrer Variablen in verschiedenen TU's haben Sie genau das getan. Hoppla!

1
Paul Sanders