Ein Programm, an dem ich arbeite, hat viele Konstanten, die für alle Klassen gelten. Ich möchte eine Header-Datei "Constants.h" erstellen und alle relevanten Konstanten deklarieren können. Dann kann ich in meinen anderen Klassen einfach aufnehmen #include "Constants.h
.
Ich habe es mit #ifndef
... #define ...
Syntax gut funktionieren lassen . Ich würde jedoch lieber die const int...
Form von Konstanten verwenden. Ich bin mir allerdings nicht ganz sicher, wie.
const int
? Beispielcode posten, der nicht kompiliert werden konnte, wenn das Ihre Frage ist?Antworten:
Sie können einfach eine Reihe von
const ints
in einer Header-Datei definieren:// Constants.h #if !defined(MYLIB_CONSTANTS_H) #define MYLIB_CONSTANTS_H 1 const int a = 100; const int b = 0x7f; #endif
Dies funktioniert, weil in C ++ ein Name im Namespace-Bereich (einschließlich des globalen Namespace), der explizit als const deklariert und nicht explizit als extern deklariert ist, eine interne Verknüpfung aufweist, sodass diese Variablen beim Verknüpfen von Übersetzungseinheiten keine doppelten Symbole verursachen würden. Alternativ können Sie die Konstanten explizit als statisch deklarieren.
static const int a = 100; static const int b = 0x7f;
Dies ist kompatibler mit C und besser lesbar für Personen, die möglicherweise nicht mit C ++ - Verknüpfungsregeln vertraut sind.
Wenn alle Konstanten Ints sind, können Sie die Bezeichner auch als Aufzählungen deklarieren.
enum mylib_constants { a = 100; b = 0x7f; };
Alle diese Methoden verwenden nur einen Header und ermöglichen die Verwendung der deklarierten Namen als Kompilierungszeitkonstanten. Die Verwendung
extern const int
einer separaten Implementierungsdatei verhindert, dass die Namen als Konstanten für die Kompilierungszeit verwendet werden.Beachten Sie, dass die Regel , dass bestimmte Konstanten implizit interne Bindung macht sich auf Zeiger anwenden, genau wie Konstanten anderer Typen. Das Schwierige ist jedoch, dass das Markieren eines Zeigers als
const
etwas andere Syntax erfordert, die die meisten Leute verwenden, um Variablen anderer Typen const zu machen. Sie müssen tun:int * const ptr;
einen konstanten Zeiger zu machen, damit die Regel auf ihn angewendet wird.
Beachten Sie auch, dass dies ein Grund ist, warum ich es vorziehe, konsequent
const
nach dem Typ zu setzen:int const
stattconst int
. Ich setze auch das*
nächste neben die Variable: dhint *ptr;
anstelle vonint* ptr;
(vergleiche auch diese Diskussion).Ich mache solche Dinge gerne, weil sie den allgemeinen Fall widerspiegeln, wie C ++ wirklich funktioniert. Die Alternativen (
const int
,int* p
) sind nur spezielle Gehäuse, um einige einfache Dinge besser lesbar zu machen. Das Problem ist, dass beim Verlassen dieser einfachen Fälle die speziellen Alternativen aktiv irreführend werden.Obwohl die früheren Beispiele die allgemeine Verwendung von zeigen
const
, würde ich den Leuten tatsächlich empfehlen, sie so zu schreiben:int const a = 100; int const b = 0x7f;
und
static int const a = 100; static int const b = 0x7f;
quelle
const
an der richtigen Stelle platzieren. Um einen Zeiger zuconst
erstellen, muss dasconst
nach dem gesetzt werden*
. ZBint * const x
. Wenn Sie nur verwenden, bezieht sichconst int *x;
dasconst
auf das, worauf der Zeiger zeigt, und nicht auf den Zeiger selbst.Ich mag den Namespace für diesen Zweck besser.
Option 1 :
#ifndef MYLIB_CONSTANTS_H #define MYLIB_CONSTANTS_H // File Name : LibConstants.hpp Purpose : Global Constants for Lib Utils namespace LibConstants { const int CurlTimeOut = 0xFF; // Just some example ... } #endif // source.cpp #include <LibConstants.hpp> int value = LibConstants::CurlTimeOut;
Option 2 :
#ifndef MYLIB_CONSTANTS_H #define MYLIB_CONSTANTS_H // File Name : LibConstants.hpp Purpose : Global Constants for Lib Utils namespace CurlConstants { const int CurlTimeOut = 0xFF; // Just some example ... } namespace MySQLConstants { const int DBPoolSize = 0xFF; // Just some example ... } #endif // source.cpp #include <LibConstants.hpp> int value = CurlConstants::CurlTimeOut; int val2 = MySQLConstants::DBPoolSize;
Und ich würde niemals eine Klasse verwenden, um diese Art von HardCoded Const-Variablen zu halten.
quelle
value
mussval2
? Gibt es eine Möglichkeit, den Namespace in die Funktion aufzunehmen und dieselben konstanten Namen wie im Namespace zu verwenden?Sie sollten zB
const int
in einer Header-Datei im Allgemeinen nicht verwenden , wenn sie in mehreren Quelldateien enthalten ist. Dies liegt daran, dass die Variablen dann einmal pro Quelldatei definiert werden (technisch gesehen Übersetzungseinheiten), da globaleconst
Variablen implizit statisch sind und mehr Speicher als erforderlich beanspruchen.Sie sollten stattdessen eine spezielle Quelldatei haben
Constants.cpp
, die die Variablen tatsächlich definiert, und dann die Variablen wieextern
in der Header-Datei deklarieren lassen .So etwas wie diese Header-Datei:
// Protect against multiple inclusions in the same source file #ifndef CONSTANTS_H #define CONSTANTS_H extern const int CONSTANT_1; #endif
Und das in einer Quelldatei:
const int CONSTANT_1 = 123;
quelle
const int
in einer Header-Datei verwenden, daconst
Variablen standardmäßig eine interne Verknüpfung haben. Ob Sie das anstelle einer einzelnen Instanz möchten, ist eine andere Frage. Normalerweise spielt es keine Rolle, solange der Wert in der Kopfzeile verfügbar ist.extern
Deklaration enthält.C ++ 17
inline
VariablenMit dieser fantastischen C ++ 17-Funktion können wir:
constexpr
: Wie deklariere ich constexpr extern?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":
cppreference https://en.cppreference.com/w/cpp/language/inline erklärt, dass, wenn
static
nicht angegeben, eine externe Verknüpfung besteht.Inline-Variablenimplementierung
Wir können beobachten, wie es implementiert wird mit:
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 überu
:Wir sehen also, dass es dafür eine dedizierte ELF-Erweiterung gibt.
C ++ 17 Standardentwurf zu "global"
const
impliziertstatic
Dies ist das Zitat für das, was unter https://stackoverflow.com/a/12043198/895245 erwähnt wurde
C ++ 17 n4659 Standardentwurf 6.5 "Programm und Verknüpfung":
Der Bereich "Namespace" wird umgangssprachlich häufig als "global" bezeichnet.
Anhang C (informativ) Kompatibilität, C.1.2 Abschnitt 6: "Grundbegriffe" begründet, warum dies von C geändert wurde:
Siehe auch: Warum impliziert const eine interne Verknüpfung in C ++, wenn dies in C nicht der Fall ist?
Getestet in GCC 7.4.0, Ubuntu 18.04.
quelle
Anstatt eine Reihe globaler Variablen zu erstellen, können Sie auch eine Klasse mit einer Reihe öffentlicher statischer Konstanten erstellen. Es ist immer noch global, aber auf diese Weise ist es in eine Klasse eingeschlossen, sodass Sie wissen, woher die Konstante kommt und dass es eine Konstante sein soll.
Konstanten.h
#ifndef CONSTANTS_H #define CONSTANTS_H class GlobalConstants { public: static const int myConstant; static const int myOtherConstant; }; #endif
Constants.cpp
#include "Constants.h" const int GlobalConstants::myConstant = 1; const int GlobalConstants::myOtherConstant = 3;
Dann können Sie dies wie folgt verwenden:
#include "Constants.h" void foo() { int foo = GlobalConstants::myConstant; }
quelle
Es scheint, dass die Antwort von bames53 auf das Definieren von ganzzahligen und nicht ganzzahligen konstanten Werten in Namespace- und Klassendeklarationen erweitert werden kann , selbst wenn sie in mehreren Quelldateien enthalten sind. Es ist nicht erforderlich, die Deklarationen in einer Header-Datei, sondern die Definitionen in einer Quelldatei abzulegen. Das folgende Beispiel funktioniert für Microsoft Visual Studio 2015, für z / OS V2.2 XL C / C ++ unter OS / 390 und für g ++ (GCC) 8.1.1 20180502 unter GNU / Linux 4.16.14 (Fedora 28). Beachten Sie, dass die Konstanten nur in einer einzelnen Header-Datei deklariert / definiert werden, die in mehreren Quelldateien enthalten ist.
In foo.cc:
#include <cstdio> // for puts #include "messages.hh" #include "bar.hh" #include "zoo.hh" int main(int argc, const char* argv[]) { puts("Hello!"); bar(); zoo(); puts(Message::third); return 0; }
In messages.hh:
#ifndef MESSAGES_HH #define MESSAGES_HH namespace Message { char const * const first = "Yes, this is the first message!"; char const * const second = "This is the second message."; char const * const third = "Message #3."; }; #endif
In bar.cc:
#include "messages.hh" #include <cstdio> void bar(void) { puts("Wow!"); printf("bar: %s\n", Message::first); }
In zoo.cc:
#include <cstdio> #include "messages.hh" void zoo(void) { printf("zoo: %s\n", Message::second); }
In bar.hh:
#ifndef BAR_HH #define BAR_HH #include "messages.hh" void bar(void); #endif
In zoo.hh:
#ifndef ZOO_HH #define ZOO_HH #include "messages.hh" void zoo(void); #endif
Dies ergibt die folgende Ausgabe:
Hello! Wow! bar: Yes, this is the first message! zoo: This is the second message. Message #3.
Der Datentyp
char const * const
bedeutet einen konstanten Zeiger auf ein Array konstanter Zeichen. Die ersteconst
wird benötigt, weil (laut g ++) "ISO C ++ die Konvertierung einer String-Konstante in 'char *' verbietet". Die zweiteconst
ist erforderlich, um Verbindungsfehler aufgrund mehrerer Definitionen der (dann nicht ausreichend konstanten) Konstanten zu vermeiden. Ihr Compiler beschwert sich möglicherweise nicht, wenn Sie eines oder beide derconst
s weglassen , aber der Quellcode ist weniger portabel.quelle