C++ 再入門 その2 streamって何?
さて、うっかり始めてしまったC++再入門ですが、大抵のプログラミング言語で最初に試す”Hello World!”から新しいことがたくさん出てきてしまいました。
C++ 再入門 その1 最初の一歩から大混乱
この短いコードだけで
stream入出力
iostreamクラス
ヘッダファイルのファイル名
名前空間
演算子
演算子の再定義
を理解しなければなりません。いきなりすべてを理解しなくても、とりあえず「ここはこう書いておく」で済ませても大丈夫ですが、ここにC++らしさが凝縮しています。
今回は手始めに「stream とはなんぞや?」から説明してみましょう。C言語の入出力は言語としての規定は無くライブラリ関数で提供されています。お馴染みの”stdio.h”に含まれるprintfやscanfといった関数で入出力を行うわけで、言語が持っている変数の型と入出力で扱われる型指定は、とても似ていますが基本的は別のものです。従ってポインタを整数の形で出力することも出来ますし、文字を数値で出してもお構いなしです。もっともいろいろな理由で思った出力にならないこともしばしば発生し、書式指定子を駆使したり、printfに渡す引き数をキャストで調整したりすることも良くあります。
こんな混沌とした機能をC++の強力なクラスの機能を上手に使って解決しようとしたのが stream 関係のクラスです。C言語はUNIXから誕生しましたが、このUNIXの特徴とも言えるのが、入出力を標準出力、(標準エラー出力、)標準入力といったテキストの流れるストリームという機構に整理したことです。これらの入出力をコンソールやキーボードであっても、ファイルであっても自由に切り替えて使うことができます。この考え方を言語自身にも取り入れて、C言語で面倒であった型の解釈と書式制御はクラスに任せようというのが、標準ライブラリである iostream クラスという訳です。
ストリームとは何か?(関数と比較しながら考えよう!)
これらのストリーム機能を使うには、printf を使う時に “stdio.h” をインクルードしたように、”iostream” をインクルードします。標準出力は cout、標準入力は cin というキーワードに “<<”や”>>” 演算子を使ってリテラルや変数を指定すれば、その型に合わせた適切な処理が選ばれます。もう printf の時のように、いくつ”%”を書いたのか数える必要はありません。
少し脱線しますが、C言語の時代、OSによって改行コードがいろいろあるために、文字列リテラルに改行コードを埋め込んでしまったために、問題が起こることが良くありました。UNIXな世界では改行コードは “\n” であって、これはLF(Line Feed)を意味する0x0aで何の問題もなかったのですが、OSによっては、改行コードがCR(Carriage Return)である0x0dであったり、CR+LFといった2バイトで改行を表すことも良くあります。昔のMacユーザやWindowsユーザであれば心当たりはありますよね。このためEOLというマクロを定義して、リテラルに改行コードを書かないようにして、環境によって適切なコードが選択されるような書き方をして回避することも行われましたが、移植の際にこのような書き方がされていることが当てに出来なかったので、ライブラリ側で何らかの変換処理を行うことも多かったです。それはそれで便利なのですが、謎のモードが導入されることになり弊害もありました。
改行コード
類似の問題はファイルの終わりを示すEOFにもあり、もうそんな混乱はやめようということで、iostream では、改行を意味する endl というキーワードが用意されることになりました。もっとも既存のコードを見る限り、ちゃんと endl を使わずに相変わらず “\n” と書いているものも多いので、改行コードのトラブルが無くなった訳ではありません。だいたいOSとしての改行コードとネットワークプロトコル上での改行コードも同じとは限りませんしね。
さて、そういうことで、変数の値を出力したければ、
cout << value;
と書くだけで良いのです。どのような出力が得られるかは、value の型ごとに決まっており、int であれば10進数の数値が文字列として出力されますし、””で囲まれた文字列であれば、そのまま出てきます。そして、これらは続けて書くことが出来るので、
cout << “Hello “ << “World!” << endl;
とすれば、”Hello World!”(改行)が標準出力(普通は画面)に出せるという仕組みです。標準ではない出力が欲しい時、例えば printf の “%x” のように int を16進数の文字列で出力したい時には、マニピュレータというキーワードを挟みます。
cout << hex << value << endl;
と書けば int である value の値を16進数に変換してから出力してくれます。同じような仕組みで浮動小数点の書式を指定したり、文字列をすべて大文字にすることも出来ます。ぱっと見、変数とキーワードの区別がつきにくいので、最終的にどんな文字列が出てくるのかは古の printf の方が想像しやすいのですが、これはもう慣れるしかありません。
ちなみに入力の場合は
cin >> a >> b;
と書くことで、適切な書式で入力された文字を a と b に代入してくれる(演算子が異なることに注意)のですが、scanf と同様に入力がうまく型に相応しい形式であるかの問題があって、いろいろなエラー処理が必要になることもあるのですが、その辺りもだいぶ扱いやすくなっています。
そしてC++の素晴らしいのが、この仕組みがクラスを上手に活用することで、自分流儀にカスタムできることです。iostream はそれなりに複雑で規模の大きいクラスなので、そこまで到達するのは大変ですが、クラスを理解するには良い教材かもしれません。
第 3 章 iostream ライブラリ
iostream プログラミング
まあ、とりあえずは cout と >> だけ使えれば出力はできます。そしてもちろん相変わらず printf も使えるのですが、これらは「混ぜるな危険」で、同じプログラムで両方使うことは避けましょう。予期せぬ結果を招くことがあります。
そういえば、C言語教室の方ではまだファイル入出力をやっていなかったなぁ。iostream ではファイルに対する入出力も出来るのですが、fprintf の話をしていませんでしたね。そろそろ、そちらも再開しますか。
では、次は名前空間をはやめに済ませてしまいますか。そんなに難しくはないのですが、これを済まさないとサンプルコードも出し難くて仕方がありません。
ヘッダ画像は、以下のものを使わせていただきました。
https://commons.wikimedia.org/wiki/File:ISO_C%2B%2B_Logo.svg
Jeremy Kratz - https://github.com/isocpp/logos, パブリック・ドメイン, https://commons.wikimedia.org/w/index.php?curid=62851110による
#cpp #プログラミング講座 #ストリーム入出力 #標準出力 #改行コード #cout #マニピュレータ #iostream #endl
この記事が気に入ったらサポートをしてみませんか?