最小限の実行可能な例
この素晴らしいC ++ 17機能により、次のことが可能になります。
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
GitHubアップストリーム。
参照:インライン変数はどのように機能しますか?
インライン変数のC ++標準
C ++標準では、アドレスが同じであることを保証しています。C ++ 17 N4659標準ドラフト
10.1.6「インライン指定子」:
6外部リンケージのあるインライン関数または変数は、すべての変換ユニットで同じアドレスを持つ必要があります。
cppreference https://en.cppreference.com/w/cpp/language/inlineは、static
指定されていない場合、外部リンクがあることを説明しています。
GCCインライン変数の実装
それがどのように実装されているかを観察できます:
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"シンボルはユニークなグローバルシンボルです。これは、ELFシンボルバインディングの標準セットに対するGNU拡張です。このようなシンボルの場合、ダイナミックリンカーは、プロセス全体で、この名前とタイプのシンボルが1つだけ使用されていることを確認します。
これには専用のELF拡張があることがわかります。
C ++ 17より前: extern const
C ++ 17より前、およびCでは、非常によく似た効果をで実現できますextern const
。これにより、単一のメモリロケーションが使用されます。
上の欠点inline
は次のとおりです。
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アップストリーム。
C ++ 17以前のヘッダーのみの代替
これらはextern
ソリューションほど良くありませんが、機能し、メモリの場所を1つしか占有しません。
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 "Constant static members"およびDesting constexpr static data会員
C
Cでは、状況はC ++ 17より前のC ++と同じです。Cで「静的」とはどういう意味ですか?
唯一の違いは、C ++ではグローバルをconst
意味static
しますが、Cでは意味がありません。C++の「静的const」と「const」のセマンティクス
それを完全にインライン化する方法はありますか?
TODO:メモリをまったく使用せずに、変数を完全にインライン化する方法はありますか?
プリプロセッサが行うこととよく似ています。
これはどういうわけか必要になります:
- 変数のアドレスが取得されるかどうかの禁止または検出
- その情報をELFオブジェクトファイルに追加し、LTOに最適化させる
関連:
Ubuntu 18.10、GCC 8.2.0でテスト済み。
const
。