C++/文法の基礎

出典: フリー教科書『ウィキブックス(Wikibooks)』
< C++

メッセージ表示するプログラムを作成してみる[編集]

ソースコードの記述から実行までの仕方は、箇条書きにすると、

  1. ソースコードをテキストエディタで書いて、sample.cpp の名前で保存。
  2. ソースコードをコンパイルする。
  3. コマンドプロンプトなどで実行する。

です。

sampleの部分はいわゆる半角英数字ならお好きな別の名前でいいですが、拡張子の .cpp は、コンパイラーがC++のソースコードだとわからなくなるので変えないでおきましょう。

ソースコードの作成と確認方法[編集]

まず、「ようこそ、C++言語へ。」とメッセージ表示をするプログラムを作成してみましょう。

sample.cpp
#include <iostream>
using namespace std;

int main() {
  cout << "ようこそ、C++言語へ。" << endl; 
}
sample.cppの部分は、オンラインコンパイル実行環境のPAIZAへのリンクになっています。

まず、このコードを「メモ帳」アプリなどのテキストエディターに書いて、「sample.cpp」のように拡張子cppをつけて、保存します。

また、「Word」などのワードプロセッサー・アプリケーションで保存しないでください。ワードプロセッサーの保存形式は、プレーンテキストではないのでコンパイルするとエラーになります。

簡単な説明
一行一行説明すると膨大になるので
  cout << "ようこそ、C++言語へ。" << endl;
について説明します。
cout はストリームオブジェクトで、標準出力に結びついています。
<< は、本来は左シフト演算子ですが、ストリームオブジェクトでは出力演算子となり右辺の式をストリームに出力します。
<< は、左結合(同じ優先度の演算子が続いたら左から評価する)なので、"ようこそ、C++言語へ。" を右辺とする式が先に評価されます。
"ようこそ、C++言語へ。" は見たままの文字列リテラルです。
endl は、改行を示すオブジェクトで、出力バッファのフラッシュを伴います(バッファリングの説明は中級編以降でおこないます)。
cout << "ようこそ、C++言語へ。" << endlまでは「式」ですが、; を付けると「文」になります。
この行全体としては、
標準出力に "ようこそ、C++言語へ。" を出力し、改行してバッファフラッシュする。
となります。
文字種
プログラミングは、ワードプロセッサーで文書を作成するの比べ、文字種に厳格です。
cout と書くべきところを coutと、いわゆる全角文字で書くと同じトークンではなくなります。
また、いわゆる半角スペース(' ')を書くべきところに、いわゆる全角スペース(' ')を書いても white space として扱われません。
エラーになる例
#include <iostream>
using namespace std;

int main() {
  cout << "ようこそ、C++言語へ。" << endl; 
}
コンパイル結果
Main.cpp:5:3: error: use of undeclared identifier 'cout'
  cout << "ようこそ、C++言語へ。" << endl; 
  ^ 
1 error generated.
use of undeclared identifier 'cout'
抄訳
未宣言識別子'cout'の使用
C言語/C++に『命令』はありません

この本でも、C言語やC++の説明に「命令」という言葉を使っていることがありますが間違いです。 C言語やC++の大きな特徴の一つは、他の言語なら命令や組込み関数として用意している入出力や演算をライブラリーとしてコア言語の外に用意していることです。 例えば sin(正弦)は、Fortran などの言語では組込み関数ですが、C/C++では標準ライブラリー <math.h>/<cmath>の関数です。 同様に、標準出力ストリーム cout は、組込みオブジェクト…ではなく、ライブラリーで定義されたインスタンスです。

「プリプロセッサーの前処理命令があるじゃないか!」という反論を時々聞きますが「前処理令」です。


コンパイルから実行まで[編集]

コンパイル[編集]

  1. ソースコードをテキストエディタで書いて、sample.cpp のような名前で保存。
  2. ソースコードをコンパイルする。 ← 今ここ
  3. コマンドプロンプトなどで実行する。

テキストエディタに保存するだけでは実行できません。

まず、コンパイルをして実行ファイルに変更する必要があります。『コマンドプロンプト』などと言われるコマンドライン端末を使います。Windowsの場合、『アクセサリ』にある「コマンドプロンプト」はそれです。

さて、コマンドラインだけでなく、コンパイラも必要なので、インストール済みである必要があります。 『C++/はじめに』にコンパイラのインストール方法などを書いておいたので、必要なら、お読みください。

コンパイル方法の結果だけ、まとめると、

  1. カレントディレクトリーにソースコードを置き、
  2. そしてコンパイラで下記のコマンドを入れます。

コンパイラの種類によって、コマンドなどが違います。

clang
clang++ ファイル名.cpp
g++
g++ ファイル名.cpp

詳しくは『C++/はじめに』をお読みください。

上記コマンドでは、出力ファイル名を指定していないので、コンパイルしたら「a.out」というファイルが作成されます。

もし出力ファイルに名前を「sample」にしたいのならば

clang
clang++ sample.cpp -o sample
g++
g++ sample.cpp -o sample

とします。

実行[編集]

  1. ソースコードをテキストエディタで書いて、sample.cpp のような名前で保存。
  2. ソースコードをコンパイルする。
  3. コマンドプロンプトなどで実行する。 ← 今ここ

コンパイル時に出力ファイル名を作成していない場合、gccやclangでのコンパイルなら、コマンド

./a.out 

で実行できます。出力ファイル名を指定しない場合、「a.out」という名前になるからです。

もし実行ファイルをコンパイル時に「sample」と命名したなら、そういう名前の実行ファイルが存在しているので、

./sample

で実行できます。

ソースコードだけを書き換えてみる[編集]

書き換えてみる[編集]

では、さきほどの「ようこそ、C++言語へ。」と表示するプログラムを実行してメッセージ表示させた直後に、

ソースコードだけを書き換えてみると、どうなるのでしょうか。

さきほどの「ようこそ、C++言語へ。」と表示するプログラムを実行してメッセージ表示させた直後に、

#include <iostream>
using namespace std;

int main() {
	cout << "ようこそ、12345。" << endl;
}

と入力して、さきほどのソースコードのファイル「sample.cpp」で上書き保存したら、どうなるでしょうか?

「sample.cpp」で保存した直後に、 コマンド端末で

./sample

を実行すると、「ようこそ、C++言語へ。」と表示されます。つまり、上書き保存した内容は、まだオブジェクトファイルには、反映されていません。

こうなる理由は、ソースコードを書き換えて保存しても、それだけでは、オブジェクトファイルは、何も書き変わらないからです。

オブジェクトファイルを、内容「ようこそ、12345。」のものに書き換えるには、

g++ sample.cpp -o sample

をもう一度、実行して、オブジェクトファイルを上書きする必要があります。

このあとに、コマンド端末で

./sample

を実行すると、今度は「ようこそ、12345。」と表示されます。


まとめ[編集]

オブジェクトファイルを、内容「ようこそ、12345。」のものに書き換えるには、

g++ sample.cpp -o sample

をもう一度、実行して、オブジェクトファイルを上書きする必要があります。

このあとに、コマンド端末で

./sample

を実行すると、今度は「ようこそ、12345。」と表示されます。

練習問題: 「hello,world」と表示させてみましょう[編集]

アメリカのプログラミングの入門書では、「hello,world」とメッセージ表示をするプログラムが、最初に紹介されることが多くあります。

この本でも、さきほど習った知識をつかって、「hello,world」とメッセージ表示するプログラムを書いてみましょう。

答えのコードは、例えば、

#include <iostream>
using namespace std;

int main()
{
	cout << "hello, world" << endl;
}

のようになります。

コードを書き替えたあとにコマンド端末でコマンド

g++ sample.cpp -o sample

などを実行してコンパイルしなおしましょう。そしてコマンド端末でコマンド

./sample

を実行して、「hello,world」を表示しましょう。

コンソール入出力[編集]

基本[編集]

標準C言語でコンソール入出力する場合、printf関数やscanf関数を使う。(文字表示ならコンソール出力なのでprintf。キーボード入力ならコンソール入力なのでscanf。)

※ printf や scanf を知らないなら、この文は読み飛ばして斜め読みでいい。

C++では、下記のようなcout やcin などのストリームを用いて、体系的な新しい方法でコンソール入出力を行うことができる。


coutやcinを使うには、 <iostream> ヘッダーをインクルードする必要がある。

コンソールへの出力は次のように行う。

cout << ;

<<演算子を複数使うことで、複数の項目を出力することもできる。

キーボードからの入力は次のように行う。

cin >> 変数;

不等号っぽいものの向きが変わっている事に注意。演算子 << と >> はまとめて「入出力演算子」と呼ばれる。

またなお cin について、scanf関数とは違い、右辺の変数に「&」が付いていないことに注意[1]

#include <iostream>
using namespace std;

int main() {
	int i = 1234;
	cout << "iの値は" << i << "です" << endl;
}
//例 コンソールから入力
#include <iostream>
using namespace std;

int main()
{
	cout << "整数を入力してください。" << endl;
	int i;
	cin >> i;
	cout << "入力された値は"<<i<<"です。" << endl;
}


なお、<<や>>は同じ形の演算子が、ビット計算のシフト演算子としても使われているが、cout や cin では別の意味で定義しています。

cout と printf の相違点[編集]

C++におけるcout(とストリーム演算子)には、出力の書式を指定できない欠点があります[2]を実現するための % 演算子の再定義もできません(そもそもプリミティブにメソッドを定義できません)。

Cのprintfでは、出力書式の指定が可能です。

コード例
#include <iostream>
#include <string> // string クラスを使うため

using namespace std;

int main() {
  int e = 3;
  cout << e << endl;

  string str = "aaaa";
  cout << str << endl;
}
表示結果
3
aaaa


いっぽう、printfを使うと、下記のように出力書式の設定が可能です。

コード例
#include <cstdio> // printfを使うため
#include <iostream>
#include <string>

using namespace std;

int main() {
  int e = 42;
  printf("%x\n", e);

  string str = "aaaa";
  printf("%s\n", str.c_str());
  fflush(stdout); // cstdio の関数と iostream のクラスを混在させるときは都度フラッシュが必要。 

  cout << str << endl; // 比較用
}
出力結果
2a
aaaa
aaaa

C++ にはstringクラスがあります。いっぽう、標準Cにはstringクラスは有りません。

printfはstringクラスのインスタンスを表示できないので、stringクラスのメソッド.c_str() 使ってprintfで表示できCの文字列型に変換します。 .c_str() は非破壊的なので、ひきつづき cout で str を表示できます。

詳しい解説[編集]

基本[編集]

ファイル名は「sample.cpp」でも「test.cpp」でも平気でして、最後の「.cpp」以外は何でもいいのですが、とにかく最後にかならず拡張子「.cpp」をつけてください[3]

コードのファイルを「sample.cpp」という名前で保存したとしましょう。

このファイル「sample.cpp」は、まだ何もコンパイルされていません。

コマンド端末で

g++ sample.cpp

のように入力してコンパイルすると、コードに間違いがなければ、「a.out」というファイル名で実行ファイルが生成されます。

なお、もしコードにエラーがあれば、「a.out」は作成されずに、かわりにコマンド端末にエラーのある事を伝えるメッセージが表示されます。

ファイル「a.out」そのものの使用をするには、コマンド端末で、

./a.out

と入力して実行することで、「a.out」を実行できます。「./」を冒頭につけるのを、忘れないようにしてください。「./」とは、カレントディレクトリー位置を意味します。通常、ログインした直後の状態では、カレントディレクトリーはホームディレクトリーに設定されている場合が多いと思いますので、ホームディレクトリーを探してください。きっと、「a.out」という名前のファイルがホームディレクトリー内に追加されているはずです。

「./a.out」というコマンドの意味は、「カレントディレクトリーにあるファイル『a.out』を実行しろ」という意味です。

この「a.out」に、さきほどコンパイルした「sample.cpp」がアセンブリ言語にコンパイルされた状態で置かれているので、よってコマンド「./a.out」の実行により、コード「sample.cpp」の内容が実行されます。

「./a.out」の実行により、コマンド端末に「ようこそ、C++言語へ。」と表示されれば、成功です。「ようこそ、C++言語へ。」と表示されていれば、正常にコンパイルされた実行ファイルを、正常に実行できた事になります。

では、ここではこのソースコード「sample.cpp」の内容について簡単に説明します。

C++言語のコード「sample.cpp」の再掲
#include <iostream>
using namespace std;

int main() {
	cout << "ようこそ、C++言語へ。" << endl;
}
  1. 行目の「#include <iostream>」は、新しいスタイルのヘッダーです。
    C言語では「#include <stdio.h>」のようにファイル名を指定しましたが、これは古いスタイルのヘッダーで、C++では新しいスタイルのヘッダーを使い、標準識別子を指定します。新しいスタイルのヘッダーは、ファイル名ではないので「.h」拡張子がありません。古いスタイルのヘッダーは、まだ使用できますが、推奨されません。標準Cヘッダーを新しいスタイルで書くと、接頭辞にcが付きます。例えば、「#include <stdio.h>」は「#include <cstdio>」となります。
  2. 行目は、std名前空間を既定にしています。C++の新しいスタイルの(STLを含む)標準ヘッダーをインクルードすると、その内容がstd名前空間に追加されます。識別子の衝突が起こっても名前空間が異なれば別個の識別子として区別することができ、名前空間自身も内包する名前空間をとてるのでちょうどファイルシステムのディレクトリのような階層構造を持つことができます。
  3. 行目は、空白行です。この空白行はなくても良いのですが、見やすくするために、空白行を入れました。
  4. 行目 int main() から8行目 } は、main関数の定義です。C++やC言語でいう「関数」とは、なんらかの一連の処理をまとめたものです。
    int は、戻値が 整数であることを示します。
    int main()で、「戻値が整数の関数 main は、引数を持たない」事を宣言しています。
  5. {から}は、ブロックというまとまりです。
    (厳密に言うと関数本体は複文(=ブロックではなく)、その証拠に return 1つしかない単文を関数本体にすることはできません)
  6. 行目(cout << "ようこそ、C++言語へ。" << endl;)は、出力演算子による出力操作です。
    Cではコンソール出力に、printf関数などを用いましたが、C++ではストリームクラスの出力演算子<<を使う方法で出力を行います。
    Cでは<<」は整数の左シフト演算子でしたが、C++ではその機能に加えて、出力演算子として用います(これは、後で解説する演算子のオーバーロードの例でもあります。)
    endlは、「改行を出力し、バッファをフラッシュする。 という意味です。なお、最後の「;」は、直前の文の終了を意味する記号です。もし、ここの「;」を書き忘れると、コンパイル時にエラーになります。他の行より、文字の位置が右から始まるのは、字下げです。字下げは、しなくても良いのですが、見やすくするために、関数の中身などを書く際に、字下げがよく使われます。


脚注[編集]

  1. ^ これは、C++固有の参照という機能の応用例。
  2. ^ この欠点が解消されるには、C++20まで導入された format() 登場まで待たなければいけませんでした。また、format() も printf() 形式ではなく Python などのプレイスホルダー形式の書式化関数です(format())。また、C++では(Kotlinの拡張関数の様に)標準ライブラリーのクラスに、新しくメソッドを定義することができないので "%f" % 3.14
  3. ^ コンパイラがどの拡張子をC++ではソースファイルとして認識するかはコンパイラのマニュアルを参照してください。 .C, .cc, c++ などのヴァリアントを受け付ける場合があります。