yohhoyの日記

技術的メモをしていきたい日記

std::coutの実体はどこ?

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 FILEs, 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 class ios_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 from stdin or write output to stdout or stderr.

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

実装:https://github.com/gcc-mirror/gcc/blob/releases/gcc-11.1.0/libstdc++-v3/src/c++98/globals_io.cc#L50-L59

// 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;

実装:https://github.com/microsoft/STL/blob/d5feb03f320ccaa8e214e3010c40c9c5afd686e2/stl/src/cout.cpp#L10-L22

#pragma init_seg(compiler)

static filebuf fout(__acrt_iob_func(1));
extern ostream cout(&fout);

可読性のため各種マクロは展開済み。init_seg(compiler)初期化順制御ディレクティブ__acrt_iob_func関数はCランタイム(CRT)の内部関数であり実装非公開。

関連URL

*1:C++03 3.5/p10: "(snip), the types specified by all declarations referring to a given object or function shall be identical, except that declarations for an array object (snip). A violation of this rule on type identity does not require a diagnostic."