C++標準ライブラリで定義されるグローバルオブジェクトstd::cout
等の宣言と定義についてメモ。
GCC/libstdc++およびClang/libcxxライブラリ実装では、宣言型(std::ostream
)と実体定義の型(char[]
)を意図的に変えている。型の不一致は厳密にはC++仕様違反*1だが、標準ヘッダ<iostream>提供グローバルオブジェクトの生存期間要件を満たすためのHACKと考えられる。たぶん。
C++03 27.3/p2より引用(下線部は強調)。
Mixing operations on corresponding wide- and narrow-character streams follows the same semantics as mixing such operations on
FILE
s, as specified in Amendment 1 of the ISO C standard. The objects are constructed, and the associations are established at some time prior to or during first time an object of classios_base::Init
is constructed, and in any case before the body of main begins execution.264) The objects are not destroyed during program execution.265)
脚注264) If it is possible for them to do so, implementations are encouraged to initialize the objects earlier than required.
脚注265) Constructors and destructors for static objects can access these objects to read input fromstdin
or write output tostdout
orstderr
.
GCC/libstdc++
宣言:https://github.com/gcc-mirror/gcc/blob/releases/gcc-11.1.0/libstdc++-v3/include/std/iostream#L61
extern ostream cout; /// Linked to standard output
// Standard stream objects. // NB: Iff <iostream> is included, these definitions become wonky. typedef char fake_ostream[sizeof(ostream)] __attribute__ ((aligned(__alignof__(ostream)))); fake_ostream cout;
Clang/libcxx
宣言:https://github.com/llvm/llvm-project/blob/llvmorg-12.0.1/libcxx/include/iostream#L53
extern ostream cout;
実装:https://github.com/llvm/llvm-project/blob/llvmorg-12.0.1/libcxx/src/iostream.cpp#L38-L42
alignas(ostream) char cout[sizeof(ostream)];
可読性のため各種マクロは展開済み。
MSVC
宣言:https://github.com/microsoft/STL/blob/d5feb03f320ccaa8e214e3010c40c9c5afd686e2/stl/inc/iostream#L40
extern ostream cout;
#pragma init_seg(compiler) static filebuf fout(__acrt_iob_func(1)); extern ostream cout(&fout);
可読性のため各種マクロは展開済み。init_seg(compiler)
は初期化順制御ディレクティブ、__acrt_iob_func
関数はCランタイム(CRT)の内部関数であり実装非公開。
関連URL