extern constのようにexternとconstを混在させることはできますか?はいの場合、const修飾子は、宣言されているスコープ内でのみ統治することを強制しますか、または宣言されている翻訳単位の宣言と正確に一致する必要がありますか?つまりsay extern const int i;
実際のiがconstではなく、その逆の場合でも?
通常のパターンは次のとおりです。
extern const int a_global_var;
#include "file.h"
const int a_global_var = /* some const expression */;
編集:legends2kのコメントを組み込みました。ありがとう。
それらを一緒に使用できます。ただし、C++が名前の修飾を行う場合、シンボル名を修飾するために使用される型情報にconstが含まれるため、constの使用には一貫性が必要です。 extern const int i
はextern int i
とは異なる変数を参照します
Extern "C" {}を使用しない限り。 C名の装飾はconstに注意を払いません。
C++ 17 inline
変数
extern const
を使用すると、実際には C++ 17インライン変数 を使用する可能性が高くなります。
この素晴らしいC++ 17機能により、次のことが可能になります。
constexpr
として保存します: 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;
}
コンパイルして実行:
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
インライン変数のC++標準
C++標準では、アドレスが同じであることを保証しています。 C++ 17 N4659標準ドラフト 10.1.6 "インライン指定子":
6外部リンケージを持つインライン関数または変数は、すべての変換単位で同じアドレスを持っているものとします。
cppreference https://en.cppreference.com/w/cpp/language/inline は、static
が指定されていない場合、外部リンケージがあることを説明します。
インライン変数の実装
以下を使用して、実装方法を確認できます。
nm main.o notmain.o
を含む:
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
およびman nm
はu
について述べています:
"u"シンボルは一意のグローバルシンボルです。これはGNU ELFシンボルバインディングの標準セットの拡張です。このようなシンボルの場合、ダイナミックリンカーは、プロセス全体でこの名前とタイプのシンボルが1つだけ使用されていることを確認します。
そのため、専用のELF拡張機能があることがわかります。
Pre-C++ 17:extern const
extern const
は以下の例のように機能しますが、inline
の欠点は次のとおりです。
constexpr
を作成することはできません。inline
のみがそれを許可します。 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.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
C++ 17以前のヘッダーのみの代替
これらはextern
ソリューションほど優れていませんが、動作し、単一のメモリロケーションのみを占有します。
constexpr
はconstexpr
およびinline
定義を表示する(強制する)ことを意味するため、inline
関数すべての翻訳単位 :
constexpr int shared_inline_constexpr() { return 42; }
そして、まともなコンパイラーは呼び出しをインライン化するに違いない。
次のように、const
またはconstexpr
静的整数変数を使用することもできます。
#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;
}
しかし、そのアドレスを取得するなどのことはできません。さもないと、odrが使用されるようになります。 https://en.cppreference.com/w/cpp/language/static "定数メンバー」および constexpr静的データメンバーの定義
完全にインライン化する方法はありますか?
TODO:メモリをまったく使用せずに変数を完全にインライン化する方法はありますか?
プリプロセッサの動作とよく似ています。
これには何らかの方法が必要です。
関連:
Ubuntu 18.10、GCC 8.2.0でテスト済み。
それらを一緒に使用でき、constキーワードを無視するあらゆる種類のことを実行できます。キーワード。これは、コンパイラーに変数を変更しないことを伝えます。これにより、コンパイラーはいくつかの便利な最適化を行うことができ、意図しないものを変更できなくなります。
Possibility.comには まともな記事 があり、さらに背景があります。