Minimal lauffähiges Beispiel
Mit dieser fantastischen C ++ 17-Funktion können wir:
- Verwenden Sie bequemerweise nur eine einzige Speicheradresse für jede Konstante
- Speichern Sie es als
constexpr
: Wie deklariere ich constexpr extern?
- Machen Sie es in einer einzigen Zeile aus einem Header
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Kompilieren und ausführen:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub stromaufwärts .
Siehe auch: Wie funktionieren Inline-Variablen?
C ++ - Standard für Inline-Variablen
Der C ++ - Standard garantiert, dass die Adressen gleich sind. C ++ 17 N4659 Standardentwurf
10.1.6 "Der Inline-Spezifizierer":
6 Eine Inline-Funktion oder Variable mit externer Verknüpfung muss in allen Übersetzungseinheiten dieselbe Adresse haben.
cppreference https://en.cppreference.com/w/cpp/language/inline erklärt, dass, wenn static
nicht angegeben, eine externe Verknüpfung besteht.
Implementierung von GCC-Inline-Variablen
Wir können beobachten, wie es implementiert wird mit:
nm main.o notmain.o
was beinhaltet:
main.o:
U _GLOBAL_OFFSET_TABLE_
U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i
notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i
und man nm
sagt über u
:
"u" Das Symbol ist ein eindeutiges globales Symbol. Dies ist eine GNU-Erweiterung des Standardsatzes von ELF-Symbolbindungen. Für ein solches Symbol stellt der dynamische Linker sicher, dass im gesamten Prozess nur ein Symbol mit diesem Namen und Typ verwendet wird.
Wir sehen also, dass es dafür eine dedizierte ELF-Erweiterung gibt.
Pre-C ++ 17: extern const
Vor C ++ 17 und in C können wir mit a einen sehr ähnlichen Effekt erzielen extern const
, der dazu führt, dass ein einzelner Speicherort verwendet wird.
Die Nachteile inline
sind:
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.cpp
#include "notmain.hpp"
const int notmain_i = 42;
const int* notmain_func() {
return ¬main_i;
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
extern const int notmain_i;
const int* notmain_func();
#endif
GitHub stromaufwärts .
Nur Header-Alternativen vor C ++ 17
Diese sind nicht so gut wie die extern
Lösung, aber sie funktionieren und belegen nur einen einzigen Speicherort:
Eine constexpr
Funktion, weil constexpr
impliziertinline
und inline
erlaubt (erzwingt), dass die Definition auf jeder Übersetzungseinheit erscheint :
constexpr int shared_inline_constexpr() { return 42; }
und ich wette, dass jeder anständige Compiler den Aufruf einbindet.
Sie können auch eine const
oder eine constexpr
statische Ganzzahlvariable wie folgt verwenden:
#include <iostream>
struct MyClass {
static constexpr int i = 42;
};
int main() {
std::cout << MyClass::i << std::endl;
// undefined reference to `MyClass::i'
//std::cout << &MyClass::i << std::endl;
}
Sie können jedoch nicht die Adresse übernehmen oder sie wird odr-verwendet, siehe auch: https://en.cppreference.com/w/cpp/language/static "Konstante statische Elemente " und Definieren statischer Constexpr-Daten Mitglieder
C.
In C ist die Situation dieselbe wie in C ++ vor C ++ 17, ich habe ein Beispiel hochgeladen unter: Was bedeutet "statisch" in C?
Der einzige Unterschied besteht darin, dass in C ++ für Globale const
impliziert static
wird, in C: C ++ jedoch nicht die Semantik von `static const` vs` const`
Gibt es eine Möglichkeit, es vollständig zu integrieren?
TODO: Gibt es eine Möglichkeit, die Variable vollständig zu inline, ohne überhaupt Speicher zu verwenden?
Ähnlich wie der Präprozessor.
Dies würde irgendwie erfordern:
- Verbieten oder Erkennen, ob die Adresse der Variablen verwendet wird
- Fügen Sie diese Informationen zu den ELF-Objektdateien hinzu und lassen Sie sie von LTO optimieren
Verbunden:
Getestet in Ubuntu 18.10, GCC 8.2.0.
const
.