標準出力に書き込む

「標準出力」というのは、慣用的な出力を行うためのテキストストリームの結合先のことで、多くの場合、画面への表示になっています。画面といっても、Windows などで見慣れたウィンドウとかではなく、コマンドライン(Windows でいえばコマンドプロンプト)です。

  コマンドプロンプト

しかし、プログラムの呼び出し方しだいで、標準出力は、画面への表示ではなく、ファイルや他のプログラムが操作するストリームに結合することもできます。例えば、CGI では標準出力への書き込みはブラウザへのレスポンスとなります。また別の状況では標準出力の結合先がシリアルポートになることもあるでしょう。

std::cout

標準出力に書き込むための最も一般的な方法は、std::cout を使用することです。std::cout に対して << 演算子を用いることで、

#include <iostream>

int main()
{
  std::cout << "Hello, World!";
}

とすれば、<< 演算子の右辺に記述したオブジェクトの値が標準出力に書き込まれます。上のサンプルコードでも分かるように、std::cout を使うときは <iostream> ヘッダをインクルードする必要があります。

また、末尾に改行を書き込みたい場合には、'n' または "n" を書き込んでもよいのですが、普通は std::endl を使用します。

  std::cout << "Hello, World!" << std::endl;

std::endl は、改行文字 n を書き込んだ後、ストリームが管理しているバッファの内容をフラッシュ(実際に吐き出)します。

std::cout を使うメリットは、<< 演算子さえ定義してやれば、ユーザー定義型も含めて、どんな型のオブジェクトであっても同じ構文で書き込み処理を記述できる点にあります。デメリットとしては、ややオーバーヘッドが大きいことが挙げられます。ただ、速度面に関しては、元々入出力は遅いものですし、サイズ面に関しては、プログラムの規模がある程度以上大きくなると、その影響は微々たるものになります。std::cout を避ける、または他の方法を用いる積極的な理由がなければ、std::cout を使うようにしましょう。

std::wcout

std::wcoutstd::cout とよく似ています。何が違うかというと、std::cout に対して書き込むことができる文字は char 型であり、文字列は char* または std::string 型なのに対して、std::wcout に書き込むことができる文字は wchar_t 型であり、文字列は wchar_t* または std::wstring 型だということです。つまり、std::wcout はワイド文字(列)を扱うためのものです。

std::coutchar 型のようなナロー文字(列)しか扱えません。逆に、std::wcoutwchar_t 型のようなワイド文字(列)しか扱えません。両方を混在させることは原則としてできないのです。どうしても混在させたい場合は、自分で << 演算子を多重定義するなどしなければなりません。 また、ひとつのプログラムの中で、std::coutstd::wcout を混在させるべきではありません。

#include <iostream>

int main()
{
  std::wcout << L"Hello, World!" << std::endl;
}

なお、処理系によっては std::wcout がサポートされていない場合があります。規格上はサポートしなければならないのですが、実際に使う処理系がサポートしないのであれば、使用を控える以外にありません。

なお、std::wcout を用いて日本語を出力したい場合には、ロケールの設定が必要になります。ロケールを設定するには、std::wcoutimbue メンバ関数を使用します。このメンバ関数に設定しようとするロケールを渡すことになります。例えば、

#include <iostream>
#include <locale>

int main()
{
  std::wcout.imbue(std::locale(""));
  std::wcout << L"こんにちは、世界!" << std::endl;
}

のようにです。上のサンプルコードでは、ロケールに "" を設定しています。日本語の OS 環境であれば、多くの場合これで問題ありませんが、もっと明示的に日本語ロケールを設定するには、処理系定義の文字列、例えば "ja" とか "japanese" などを渡す必要があります。

処理系によっては、std::setlocale によってグローバルロケールを設定しておかないと誤動作することがあります。処理系の不具合ですが、ときどき遭遇するので要注意です。

stdout

最後は C との互換性のために用意された stdout を使う方法です。std::cout の使い方が分からないといった後ろ向きな理由を除けば、std::coutstd::wcout ではなく、stdout を使わなければならない状況は多くありません。しかし、例えば FILE* 型の他のストリーム(テンポラリファイルやパイプなど)と出力先を切り替えたい場合などは、そうせざるを得ないこともあるでしょう。

stdout を用いて標準出力に文字列を書き込むには、

#include <cstdio>

int main()
{
  std::fputs("こんにちは、世界!n", stdout);
}

のようにします。数値を書き込むには、printf または fprintf を使うことになりますが、オブジェクトの型によって異なる書式を指定しなければなりません。

#include <cstdio>

int main()
{
  std::printf("%d %fn", 123, 4.56);
}

printf 等では、第 1 引数である書式文字列に続く引数の型はまったくチェックされません。また、クラス型のオブジェクトを引数に渡すと未定義の動作を引き起こします。そのため、プログラマの責任で正しい書式を記述しなければなりません。