Welcome to Mashykom WebSite



C/C++言語 :コーディング入門


 C言語は、1972年にアメリカAT&T社ベル研究所のデニス・M・リッチー(Dennis M. Ritchie)氏とブライアン・W・カーニハン(Brian. W. Kernighan)氏によって開発されました。開発の目的は、UNIXの移植性を高めるためでした。UNIXの大部分はC言語によって書かれています。特定のプラットフォームに依存した部分を言語仕様から切り離しているため、移植性の高いプログラムを書くことができます。

 C言語の特徴としては、以下のことがあげられます。手続き型の汎用プログラミング言語で、構造化プログラミングに適している。プラットフォーム依存の言語仕様がないため、プログラムの移植性が高い。コンパイラ言語であり、プログラムの実行速度が速い。この理由から、C言語はOS等の記述に多く使われているため、OS周りのシステムや組み込み・ハードウェア領域、IoTと言われる分野ではC言語が使用される場面が多いです。

 オブジェクト指向言語のC++は1983年にベル研究所の科学者であるビャーネ・ストロヴストルップ氏によってC言語の拡張版として開発されました。C++の大きな特徴としては、C言語との互換性があることです。そのため、C言語を用いて作られたシステムをC++に移行するのは簡単ですし、CプログラマやCと構文が似ているJavaプログラマがC++を学ぶことは容易に可能です。C++はC言語およびそのプリプロセッサの構文をほぼ継承しています。

 C++言語の最初の標準は1998年にISO/IEC 14882:1998として承認された。2003年の改訂版を経て、2011年にメジャーアップデートとして制定されたのが、通称「C++11」である。また、2014年にはISO/IEC 14882:2014、通称「C++14」が策定された。2017年にはISO/IEC 14882:2017、通称「C++17」が国際規格とされた。

 ロボット等の制御にC/C++が使われることがあるため、プログラミング初心者でもC/C++から入る人たちがいます。ただ、初心者が最初に学ぶ言語として安易にC/C++を選ぶのは良くありません。C/C++言語はOSの開発やプログラミング言語自体の開発などには欠かせない存在で、とても重要な言語であることは事実です。 しかし、C/C++にはとても難解な概念が登場します。言語を習得したところで初心者にも作りやすいアプリを作れないという、プログラミング学習の挫折につながりやすい言語なのです。

ゲームやスマホアプリ、Webアプリ、人工知能(AI)などを開発したい場合には不向きな言語です。プログラミングでも、Webアプリを作りたければWeb向けの言語(Ruby, Javascript)を、スマホアプリを開発したければスマホアプリ向けの言語(Swift)を最初に学ぶのが良いと思います。Web デザイン向けの言語JavaScriptに関する説明はこちらのページにあります。 AIやDeep Learningなどを勉強したいならPythonの勉強を勧めます。ライブラリはPython向けのものが圧倒的多数ですし、Jupyter Notebookを始め研究向きの環境も整っています。それらを習得した後に、C/C++を学んでも遅くはありません。PythonのTutorialsはこちらのページにあります。

 私は、Raspberry Piを用いたRobotの操作に興味があって、C/C++のコードを少々いじる必要があったので、C++言語の勉強を少々しました。このページでは、この経験をもとに、オブジェクト指向言語であるC++の基本的な使用法を説明します。使用しているOSはMac OSです。

Last updated: 2019.9.30



C++ソースコードのコンパイルと実行



 コンピュータが実行できる言語はマシン(機械)語と呼ばれるプログラミング言語で書かれたプログラムだけです。それ以外の言語で書かれたプログラムはすべてマシン語に翻訳する必要があります。この翻訳をする方法にコンパイラを使う方法と、インタープリタを使用する方法があります。C++で書かれたプログラムはコンパイラを用いてマシン語に翻訳して、コンピュータに実行されます。後者のインタープリタを用いて翻訳をするプログラミング言語として、PythonやJavaScriptなどがあります。

 例えば、オブジェクトとしての長方形の集合を考える時、長方形を定める属性は「たて」と「よこ」の長さだけです。長方形の面積は「たて」と「よこ」の積で計算できます。「たて」と「よこ」の長さを属性として持つ抽象的な図形を長方形のクラスと言います。このクラスは具体的な長方形のすべてを抽象化した概念です。クラスに対して、「たて」と「よこ」の長さを定めた図形をインスタンスと言います。

 オブジェクト、クラス、インスタンスという概念を用いてプログラミングすることをオブジェクト指向プログラミングと言います。C++はオブジェクト指向言語です。

 C++のプログラムを作成するためには、プログラムをコンパイルするコンパイラと、プログラムを書くエディターが必要です。よく知られているコンパイラは以下の通りです。

 独自のエディターを使用することもできますが、統合型開発環境(IDE)を利用することは最も便利は方法です。主要なIDEを以下に挙げます。

 NetBeans IDE は無償のオープンソースソフトウェアで全世界のコミュニティーユーザーと開発者に支援されています。 ユーザーインタフェースは日本語に翻訳されているのでどなたでも簡単に使えます。ダウンロードサイトは こちらです。

 日本語 Eclipse の ディストリビューションサイト、つまり、 Pleiades – Eclipse 日本語化プラグインのサイトは こちらです。 OSDN(オーエスディーエヌ)は、日本の OSS(オープンソースソフトウェア)プロジェクト向けのホスティングサイトです。

 MacOSでXcodeを用いてコンパイルする方法について簡単に説明します。Xcodeを起動させます。「Create a new Xcode project」をクリックして開きます。「macOS」->「Command Line Tool」を選び、「next」に行きます。「product name」を書き込んで、「Language」で C++を選択します。新しい画面が登場して、エディターに、開始用のHello World コードが書かれています。このコードを消去して、自らのプログラムを書き入れます。左上にある三角形の実行ボタンをクリックします。すると、成功すれば、「Build Succeeded」と出て、結果が表示されます。C++のソースコードから機械語に変換する過程を "build"するといいます。

 IDEを利用しない場合に、プログラムをコンパイルする方法を説明します。以下のC++プログラムをテキストエディターで作成して、hello.cppとして保存して下さい。


#include <iostream>

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

ターミナルを開いて、hello.cppファイルと同じディレクトリに移動して、

$clang++ -o hello.o hello.cpp

とすると、実行ファイルがhello.oとして生成される。同じく、g++ 命令も使用できます。コンパイル後の実行は以下のコマンドを入力します。


$./hello.o

結果は

Hello, World!

と表示されます。

なお、


$clang++ hello.cpp

とすると、実行ファイルがa.outとして生成されます。

 一つのC++のソースファイルをコンパイルすることは非常に単純です。C++のプログラム全体は、多数のソースプログラムが相互依存した形で構成されていますので、これら全体を一度にコンパイルすることは単純な操作ではありません。このときには、makefile と呼ばれるファイルを介したコンパイルが行われます。この説明は、後で行います。


C++言語の初歩的説明



 C++の基本的な文法を説明するために、初めに上記のhello.cppファイルの説明をします。最初にある #include <iostream> はヘッダの読み込みといわれるもので、ヘッダの <iostream> を読み込んで以下で利用することを宣言します。 <iostream> は入出力関係のヘッダで、 cout を使用するために必要となります。 cout はコンソールに表示するコマンドです。\n は改行命令です。main(){...}内の処理が実行されます。std::cout は名前空間 std 内の cout を使用することことを宣言します。:: スコープ演算子と言われます。同一の名前空間を何度も書くことを避けるために、


 using namespace std; 

と最初に書いておくこともできます。

hello.cppを以下のように書き換えても同じです。>


#include <iostream>
using namespace std;
int main() {
	cout << "Hello, World!"<< endl;
}

coutは画面を表わし、<<は「そこへ押し込め」などの意味です。したがって、


cout << "文字列"

と書くと、「文字列を画面に押し込め」つまり「文字列を画面に出力せよ」という意味になるのです。また、endlは「改行」を表わし、「;」は「命令の終わり」を意味します。そのため、

cout << "Hello World." << endl;

とすると、「出力の最後に画面に改行を押し込む」つまり「最後に改行する」という意味になるのです。int は integer の略で、整数で処理することを意味します。処理の最後は必ずセミコロン ; を置きます。

 C++の標準ライブラリを使うには、ライブラリごとに対応した#include文を書かなければならない。coutを使用するためにはヘッダ<iostream> を、三角関数を使うためには<cmath>を、stringを使用するためには<string>を等々。それはあまりにも煩雑なので、標準ライブラリのヘッダーファイルの多くを#includeしたヘッダーファイル(header file)を作成し、それを#includeすることで、#includeを書かなくて済むようにすることもできます。そのためにはまず標準ライブラリのヘッダーファイルの多くを#includeしたヘッダーファイルを作成します。詳細は省略します。

 ソースコードにコメントを書く方法は2種類あります。1行のコメントは


// コメントです

と書きますが、複数行に渡るときは、

/*
コメントを書きます
*/


と書きます。


変数とデータの型



 C++で取り扱えるデータの型と変数名について説明します。Python や Javascript などのオブジェクト指向言語と同様に、データを格納するために変数を使います。C++では、変数名は識別子(Identifiers)とも言われます。

 識別子は英文字の小文字と大文字、数字、アンダースコア(_)、および Unicode 文字 の任意の長さが用いられます。 有効な識別子は数字以外の文字で始まらなければなりません。 識別子は英文の大文字と小文字が区別され、すべての文字が有意です。変数名には英単語名を使用して、その一文字めには小文字を使うことが推奨されています。予約語と重複する可能性があるので、アンダースコアを先頭に使用することも避けた方がいいです。C++では、いくつかのキーワード(Keywords)が使われている。これらのキーワードは、プログラム中で特別な意味を持つので、識別子に使うことはできない。詳細は、江添亮のC++入門を参照ください。

 変数のデータにはあらかじめ定められた基本型があります。以下の通りです。

 変数の使用を開始するためには、データの型と変数名の使用を宣言し、変数のためのメモリ領域を確保して、変数の最初の値を設定する必要があります。例えば、以下のように宣言して、変数の値を確定します。変数の値を途中で、代入式で変更することもできます。


int a = 12345;
int a(12345);
int a{12345};
int a = {12345};
a = 23456;

 これらの宣言( declarations )におけるintは指定子( specifiers )と言われ、変数a(関数など)を宣言子( declarators )と言います。指定子は複数指定できます。宣言子は、変数や関数、型などを、ひとつ宣言します。宣言子も複数指定できる。宣言に const を付けると変数は定数として扱われて、途中で変数の値を変更することはできません。以下の例は指定子を二つ指定しています。


const int b = 56789;
b=12345;// エラーとなります

 上記の変数 a や b はオブジェクトとしてメモリー上に構築されます。データの基本型を持つ変数や、ユーザーが定義したクラス(後で説明します)も、すべてオブジェクトとして生成されます。ただし、関数は、オブジェクトではありません。オブジェクトは、変数の宣言や、newによって生成されるものです。

 リテラルという言葉が頻繁に登場します。リテラルとは、「文字通り」という意味で、数値で表現されたときは数値で、文字表現の時は文字として取り扱うことです。浮動小数点リテラルは、10進法や指数表現が取られます。浮動小数点リテラルの型は通常、doubleです。文字リテラルは、二重引用符(")で囲みます。例えば、"Hello World1" のように書きます。文字リテラルの中では、バックスラッシュは、特別なエスケケープシーケンスとして扱われる。そのため、バックスラッシュを直接使うことはできません。なお、エスケープシーケンスは、以下の通りです。


改行 new-line NL(LF) \n
水平タブ horizontal tab HT \t
垂直タブ vertical tab VT \v
バックスペース backspace BS \b
キャリッジリターン carriage return CR \r
フォームフィード form feed FF \f
アラート文字、ベル文字 alert BEL \a
バックスラッシュ backslash \ \\
疑問符 question mark ? \?
単一引用符 single quote ' \'
二重引用符 double quote " \"

 C++言語の説明でよく登場する言葉に参照とポインタという概念があります。参照と仕組みを使って、変数に別名を与えることができます。参照は以下のようにして設定します。


型名& 変数の別名 = 元の変数名;

具体的には以下のようにして使います。


#include <iostream>
using namespace std;

int main() {
	float x =12.5;
	float& y = x;
	y = 150.5;

cout << x << endl;//x = 150.5
}

変数yに代入したデータは変数aにも代入されます。

ポインタとは、変数のアドレスを記憶する変数のことです。アドレスとはメモリ上に与えられた番号のことです。変数を宣言すると、その変数にアドレスすなわちメモリ上の番号が与えられます。アドレスにアクセスすることで変数の値を取得することができます。アドレスはデフォルトでは16進数で表されます。また、ポインタ変数は整数の加減算ができます。


型名* 変数名 = 対象となる変数のアドレス;

 このように、ポインタ変数は変数名の前に「*」(アスタリスク)を付けて宣言します。ポインタ変数には変数のアドレスを代入します。変数のアドレスは変数名の前に「&」(アンパサンド)を付けて表します。変数とポインタ変数は同じ型である必要があります。以下の例の通りに使用します。


#include <iostream>
using namespace std;

int main() {
	float x =12.5;
	float* px = &x;
	*px = 150.5;

cout << x << endl;// x=150.5
}


演算子



 プログラムの基本的な構成要素の一つに式があります。この式の表現では、演算子を用いた演算が必要です。これらの演算子の表現はオブジェクト指向言語の多くと共通した様式となっています。算術演算子、比較演算子、および論理演算子については説明するまでもなく知られている通りです。以下に例を挙げます。


#include <iostream>
using namespace std;

int main() {

  //算術演算子
  cout << "算術演算子の結果" << endl;
  cout << (3 /2 ) << endl; // 出力値:1
  cout << (3 /2.0 ) << endl; // 出力値:1.5
  cout << (10 % 4) << endl;//出力値:2
  cout << (1 + 2 * 3) << endl;//出力値:7

  //比較演算子
  cout << "比較演算子の結果" << endl;
  cout << (1 < 2) << endl;//出力値:1(trueを意味する)
  cout << (3 < 2) << endl;//出力値:0(falseを意味する)

  //論理演算子
  cout << "論理演算子の結果" << endl;
  cout << (1 < 2 && 2 < 3) << endl;//論理積の出力値:1(trueを意味する)
  cout << (1 < 2 && 3 < 2) << endl;//論理積の出力値:0(falseを意味する)
  cout << (2 < 1 || 1 < 2) << endl;//論理和の出力値:1(trueを意味する)
  cout << (!(2 < 1))       << endl;//論理否定出力値:1(trueを意味する)

   //代入演算子
  cout << "代入演算子の結果" << endl;
  int x = 0;
  cout << (x = 5) << endl;//出力値:5(演算子の評価結果)
  cout << x       << endl;//出力値:5(演算子の副作用)
  int y, z;
  cout << (y = z = 5) << endl;//出力値:5(演算子の評価結果)
  cout << y << endl;          //出力値:5
  cout << z << endl;          //出力値:5

}

整数と整数の計算結果は整数です。だから、3/2の結果は1となります。浮動小数点数の入った計算結果は浮動小数点数で表示されます。なお、特殊な演算子にインクリメント演算子(++)とデクリメント演算子(--)があります。

 int i=5, j=5;

cout << (++i) << endl;//6と表示される
cout << (j++) << endl;//5と表示される

 (++i)とインクリメントを前に書くと、iの値に1を加えた後の値が出力されます。(j++)と後ろに置くと、jの値に1を加える前の値が出力されます。この処理の後、i、jの値は6になっています。


条件分岐文



 プログラミングでは、条件分岐文あるいは制御文を用いて実行順序を制御することがで重要です。最初に、while文を取り上げます。while文は次のように書かれています。このプログラムは,条件が正しい限り、中カッコのなかの処理の文を実行しなさいという命令です。C++では、文(statement)とは、';'で区切られた命令を指します。


    while(条件){
        処理の文
    }

下の例をみてください。


//while_1.cpp
#include <iostream>
using namespace std;

int main()
{
    int i;
    i = 0;
    while(i < 10){
        cout << "Hello World." << endl; 
        i++;  //iを1増やせという意味です。
    }
}

変数iを1づつ増加させていって、ちょうど10になった時、この条件が満たされなくなるので、while文の処理は終了します。

 次に、for文を取り上げます。上記のwhile文をfor文で書き換えると、以下のようになります。


/for_1.cpp
#include <iostream>
using namespace std;

int main()
{
    int i;
    for(i = 0; i < 10; i++){
        cout << "Hello World.\n";
    }
}

for文は

for(文; 条件式; 式){
	処理;
}

という形式で書かれます。このようなfor文があると、まず文が実行され、条件式の評価がtrueである限り、式と処理の実行が繰り返されます。

 条件分岐文の最後に、if文を取り上げます。if文は


if ( 条件 ){
	処理;
}
[else 処理;]

という形式で書かれます。このif文は、まず条件の評価がtrueである限り、処理の実行が繰り返されます。以下に例を挙げます。else文は省略できます。


#include <iostream>
using namespace std;

int main() {
  int n = 15;
  if (n % 2 == 1) {
	cout << "nは奇数です。\n";       //出力値:nは奇数です。
	cout << "偶数ではありません。\n";//出力値:偶数ではありません。
  }
}

 15を2で割った時の剰余が1と等しいならば、処理文を実行します。15は明らかに奇数なので、条件の評価はtrueになります。

 printf関数で変数を表示するには、「%」記号と変数の型を表す変換指定子を使用します。変換指定子の使い方について、サンプルコードで確認していきましょう。以下の例をみてください。

#include <stdio.h>
 
int main(void) {
    char *str1 = "Hello";
    char *str2 = "World";
    char chr1 = '!';
 
     // 文字および文字列
    printf("%s %s%c\n", str1, str2, chr1);
 
    double d1 = 1.234567;
    double d2 = 12.34567;
    double d3 = 123.4567;
 
    // 浮動小数点数
    printf("d1:%f\n", d1);
    printf("d2:%f\n", d2);
    printf("d3:%f\n", d3);
  
    return 0;
}

sは文字列、cは文字、fは浮動小数点数の変換指定子です。ちなみに、dは10進の整数に対応します。


関数



 ここで、関数の使用法について説明します。関数の定義は以下の様式で行います。


戻り値の型 関数名(引数の型 引数1,...){
	処理の文;
}

 戻り値を持たない関数では、戻り値の型をvoidとします。以下に例を挙げます。numOfDivisorsが関数名です。引数はn(整数)です。divisors(整数)が戻り値となります。


#include 
using namespace std;

int numOfDivisors(int n) {
  int divisors = 0;
  for (int i = 1; i <= n; ++i) {
    if (n % i == 0) ++divisors;
  }
  return divisors;
}

int main() {
  //10から20までの数の約数を数える
  for (int n = 10; n <= 20; ++n) {
    int result = numOfDivisors(n);
    cout << n << "の約数の数:" << result << endl;
  }
}

 このプログラムは10から20までの整数の約数の数を計算するものです。Xcodeでコンパイル、実行した結果はこうなります。

10の約数の数:4
11の約数の数:2
12の約数の数:6
13の約数の数:2
14の約数の数:4
15の約数の数:4
16の約数の数:5
17の約数の数:2
18の約数の数:6
19の約数の数:2
20の約数の数:6
Program ended with exit code: 0

配列



 ここで、配列(array)の定義と使用法について説明します。配列の宣言は,次のように書きます。


  要素のデータ型 配列名[要素の個数];

たとえば,int型(整数型)の要素を10個持つ,名前が a の配列は次のように宣言します。


  int a[10];

配列の各要素には,先頭を0番として,0, 1, 2, 3, ...と,順に番号がついている。 先頭が0番であることから,要素数が 10個の場合には配列の最後の要素は 9番目になります。この宣言では配列aのメモリが確保されただけで、要素の値は設定されていません。配列を宣言したときに,以下のようにして,その初期値を同時に設定する(初期化する)ことができます。この場合,10個のint型要素をもつ配列aが宣言されると同時に,その各要素の数値が設定されます。


    int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9,10};

 行列や表のように,2次元的な広がりをもって配置されたと考えるデータを取り扱うために,2次元配列があります。 その宣言は次のようにします。


  要素の型 配列名[行数][列数];

 たとえば,int 型の要素が3行4列の形に並んだ2次元配列aを宣言するには,


  int a[3][4];

とします。2次元配列の初期値の設定も1次元配列と同様に行えます。メモリ上の配置が行ごとにまとまっていることから,各行の数値列を { } で括ったものを並べて,それら全体を外側からもう一度 { } で括るという方法をとります。3行4列の行列は以下のように設定します。


    int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

次のプログラムは,配列 b の初期値を設定しておき,b の各要素の内容を a の対応する要素に代入し,a の各要素の数値を表示して確認するためのものです。



#include <stdio.h>

int main()
{
    int a[3][4];
    int b[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    int i, j;
    
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            a[i][j] = b[i][j];
        }
    }
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            printf("a[%d][%d] =%3d    ", i, j, a[i][j]);
        }
        printf("\n");
    }
}


クラス



 C++のプログラミングでよく使用されるクラスの定義の仕方を説明します。C言語では、構造体と言います。オブジェクトの属性や操作は、C++では、データメンバ(メンバ変数)、メンバ関数と呼ばれます。メンバ関数はPythonやJavaScriptではメソッドと呼ばれるものに対応します。 クラスは以下のような構文で定義します。


struct  クラス名 {
	データメンバの型 変数名;

}

同好サークルなどの名簿作成について考えると、メンバーの名前、年齢、メールアドレスなどのリストを作成することになります。クラスの概念を使用しないで、これらのリストを作る時は、以下のようにします。


string names[] = {"壮太", "里菜"};
int ages[]= {54, 52};

 メンバーの入れ替わりが膨大になったりすると、そのための修正も大変になります。そこで、クラスを定義して対応することが便利になります。これに対応したクラスの定義は


struct nakayoshiClub {
	string name;
	int age;
}

として、以下のように個人データを入力します。クラス名はnakayoshiClubとしています。


nakayoshiClub souta;
souta.name = "壮太";
souta.age = 54;

オブジェクトの属性(データメンバ、メンバ変数)はnameとageになっています。コード全体を書くと以下になります。



#include <iostream>
#include <string>
using namespace std;

struct nakayoshiClub {
  string name;
  int age;
};

int main() {
  // nakayoshiClubのオブジェクト souta を構築
  nakayoshiClub souta;
  souta.name = "壮太";
  souta.age = 54;
  cout << souta.name << endl;//出力値:Taro (32)
  cout << souta.age << endl;
}

文字列を使用しているので、ヘッダが必要となっています。メンバ関数を持つ例を以下に挙げます。


#include <iostream>
#include <string>
using namespace std;

struct Dog
{
private:
    string name;
public:
    Dog(string s){  
        name = s;
    }
    void wan(){  
        cout<<"わんわん。私の名前は"<<name<<"です。"<<endl;
    }
};

int main()
{
    Dog shelty("アンジー");  

    shelty.wan();
}

 nameはクラスDogのデータメンバです。Dog(string s)とvoid wan()はメンバ関数です。クラス名と同名の関数は、特別なものでコンストラクタとよばれるます。Dog(string s)はコンストラクタです。Dog shelty("アンジー")は 「アンジー」という名前を持ったshelty(オブジェクト)を生成する命令です。「private」と「public」の役割については無視してください。

structの他にclassを用いて以下のようにクラスを定義することもできます。


class MyClass{
  string name;
  int age;

};

 メンバ関数を定義するときの構造はこうなります。


class クラス名
{
private:        // ~~非公開部分~~

    データメンバ
    ・・・
        
public:         //~~公開部分~~
    
    メンバ関数    
    ・・・
}

structを用いるときと、classを用いて定義するときの相違、メンバ関数の取り扱いの詳細については話がかなり難しくなりますので、ここでは省略します。C++の文法に関する簡単な解説は、C++言語の参考書などを参照ください。


C言語とC++との関係



 ここで、C++とC言語におけるコーディングの若干の相違を見てみましょう。C言語での"Hello World."のコードは以下のような形式をとります。


#include <stdio.h>
 
void main(){
    printf("HelloWorld.\n");
}

#include文を最初に置くことは同じです。using namespaceはありません。この例では、main関数の頭に戻り値の型名ではなくvoidが置かれています。void型は、数値型や文字型とは異なり、戻り値が無い関数のデータ型のことです。処理の結果を戻す必要が無い場合は、void型で関数を定義すれば、最後にreturn文を書く必要はありません。main関数もvoid型とすることは可能です。void型にすれば、最後の「return 0;」は要らなくなります。main関数がint型かvoid型かで違いが出ることはありません。以下の例を見てください。



#include <stdio.h>
 
int func1(int x) {
    int y;
    y = x + 1;
    return y;
}
 
int main(){
     
    // insert code here...
    int x = 1;
    x = func1(x);
     
    printf("x = %d \n", x);
     
    return 0;
}

C言語における構造体の使用例は以下のようになります。


#include <stdio.h>
#include <string.h>
 
struct person {
    char name[40];
    char job[40];
    int age;
    int phone;
};
 
void showStatus(struct person chara) {
    printf("名前:%s\n", chara.name);
    printf("職業:%s\n", chara.job);
    printf("年齢:%d\n", chara.age);
    printf("phone:%d\n", chara.phone);
}
 
int main(int argc, const char * argv[])
{
     
    // insert code here...
     
    //souta
    struct person souta;
    strcpy(souta.name, "壮太");
    strcpy(souta.job, "教師");
    souta.age = 40;
    souta.phone = 12345;
     
    showStatus(souta);
    
     //hanako
    struct person hanako;
      strcpy(hanako.name, "花子");
      strcpy(hanako.job, "プログラマー");
      hanako.age = 45;
      hanako.phone = 23456;
    
     
    showStatus(hanako);
     
    return 0;
}

 このコードを実行すると、以下のような結果が表示されます。このプログラムではmain関数の引数を一般的な形式で明示していますが、この例では実行する上では書く必要はありません。MacOSの場合、C++と同様にXcodeを用いて、LanguageのオプションでCを選択すればコンパイルできます。

名前:壮太
職業:教師
年齢:40
phone:12345
名前:花子
職業:プログラマー
年齢:45
phone:23456
Program ended with exit code: 0

以上の例から理解できる通り、C++とC言語のコーディングの形式は同一ですが、マイナーな相違点はあります。例えば、C言語での関数のプロトタイプ宣言で、引数に何も値を受け取らない場合はvoidを明示する必要があります。しかし、C++では任意です。詳細はC言語の参考書などを読んでください。このweb siteも参考になるでしょう。


Makefileを用いたビルドの方法



 GNU makeコマンドを使えば、Makefileにあらかじめ記述しておいた手順にしたがって、C/C++などのソースファイルから実行ファイルを自動で生成できます。例えば、単一のC++ソースのhello.cppというファイルをコンパイルする場合は


$ g++ hello.cpp -o hello

と実行するとhelloという実行ファイルが生成されます。これを最も単純なMakefileを使って書くと次のようになります。


hello: hello.cpp  
	g++ -Wall hello.cpp -o hello  #実行コマンド
clean:
	rm -f *.o hello

 Makefileの書式を簡単に説明すると、Ruleとは、上記の hello: や clean: から始まる行からその下のインデントされた行までのブロックのことを指します。各Ruleは ターゲット (target) 、 必須項目 (prereq) 、 実行コマンド (commands) の3つの構成要素で成り立っています。


target: prereq1 prereq2
    commands

 1行目に生成したいターゲットファイル名(例えば、hello): 依存ファイル(hello.cpp)、2行目に生成するための実行コマンド(g++ -Wall hello.cpp -o hello)を記載します。実行コマンドの先頭にはTabを入力する必要があります。-Wallオプションは、全ての警告オプションを結合してくれるもので、一番厳密に文法をチェックします。

 ソースファイルと Makefileを同じディレクトリに配置します。プログラムを構築するには、ターミナルのディレクトリをMakefileと同じディレクトリに移動させて、コマンドプロンプトに次のように入力し make を実行します。


 $ make

 これにより make は Makefile を読み込み、次のように最初のターゲットを構築 します。


 $ make
  g++ -Wall hello.c -o hello

 helloという実行ファイルが生成されます。生成された実行ファイルを消去したい場合は「make clean」と実行すると、rm -f *.o helloのコマンドが実行されます。

 プログラム全体が、相互依存した複数のソースファイルから構成されているケースが一般的です。こうしたソースファイルを効率的にビルドする方法の一つがMakefileを活用することです。以下の例は、2つのソースプログラムからなるコードのコンパイルです。ソースはmain.cpp、および、function.cppから構成されているとします。mainの中で利用したい関数をfunction.cppのなかに記述しています。この時、Makefileは以下のようになります。


main: main.o function.o
	g++ -Wall -o main main.o function.o 
function.o: function.cpp
	g++ -Wall -c function.cpp 
main.o: main.cpp
	g++ -Wall -c main.cpp
clean:
	rm -f *.o main

 最初のルールのコマンド行に「 g++ -Wall main.cpp print.cpp -o hello」 と記述すると、コンパイルの実行が毎回両方のファイルに適用されてしまいます。片方のファイルだけを修正したい時もあります。この理由から、上記の例のように各生成ファイル毎に記述を分離するのが一般的です。

 シンボルを使ったMakefileの例を以下に示します。


CC = g++
CFLAGS = -g -Wall

ALL: main.o function.o
	$(CC) $(CFLAGS) -o main main.o function.o

main.o: main.cpp
	$(CC) $(CFLAGS) -o main.o -c main.cpp

function.o: function.cpp sub.h
	$(CC) $(CFLAGS) -o function.o -c function.cpp

 function.cppのなかでヘッダファイル sub.h を使用しています。オブジェクトファイル main.oとfunction.oを-cフラグで別々に生成してから、ALLの処理でリンクしています。make コマンドを実行すると


cpp $ make
g++ -g -Wall -o main.o -c main.cpp
g++ -g -Wall -o function.o -c function.cpp
g++ -g -Wall -o main main.o function.o

となります。mainという実行ファイルが作成されます。./main とコマンドを打つと実行ファイルが結果を表示します。

 Makefile の使用法についてよく知りたい人は、GNU make の公式マニュアルを参照ください。また、少し古いですが、 GNU make の参考書(Robert Mecklenburg 著、矢吹 道郎 監訳、菊池 彰 訳)の pdf が https://www.oreilly.co.jp/library/4873112699/からダウンロードできます。


CMakeを用いたビルドの方法



 C++のコンパイラはOSに依存して複数のコンパイラが存在しています。標準C++ライブラリだけを使ったソースコードであればどのコンパイラでもビルドすることができますが、コンパイラのオプションなどの仕様が異なります。CMakeではCMakeLists.txtという設定ファイルを作成しておけば、そこからCMakeがサポートする任意の実行ファイルを作成することができます。 つまりOSに依存せず、どの開発環境でもプロジェクトをビルドできるようになります。CMakeはクロスプラットフォームなC++プロジェクトを開発するために欠かせないツールとなっています。

CMakeは、公式サイトのダウンロードページからインストーラーをダウンロードできます。コマンドラインから、 cmake -help と入力して、ヘルプが出れば、インストールが完了しています。

CMakeを用いてコンパイルする時の設定ファイルが、CMakeLists.txtです。ビルドしたいソースコードのあるディレクトリに、CMakeLists.txtファイルを作成します。例えば、上記のhello.cppというソースファイルから、実行ファイルmainを生成するためのプロジェクトは、以下のように書きます。


cmake_minimum_required(VERSION 3.1)
project(hello_world CXX)
add_executable(main hello.cpp)

実は最後の行だけ書いておけば一応動くのですが、最低限やっておきたいという設定がこの3行です。1行目のcmake_minimum_required(VERSION 3.1)はCMakeのバージョンを指定するコマンドです。バージョンの確認に加えて暗黙的にcmake_policyコマンドを呼び出し、このCMakeLists.txtをCMake 3.1の仕様で解析するように設定が行われます。

2行目のproject(hello_world CXX)はプロジェクト名とプロジェクトで使用するプログラム言語を指定しています。ここで定義したプロジェクト名は、Xcodeのプロジェクトファイル名に使われます。

3行目のadd_executable(main hello.cpp)はビルドする実行ファイル名とそれを構成するソースファイルを指定しています。 「hello.cppを使ってmainという名前の実行ファイルを作成する」という設定になります。

 cmakeは、カレントディレクトリに生成物やキャッシュ等を色々と生成するため、ディレクトリを汚します。この理由から、「build」のようなディレクトリを作成し、そこへ移動してから、一つ上のディレクトリを渡してcmakeを実行します。


$ mkdir build 
$ cd build 
build $ cmake .. 

 ..の部分はCMakeLists.txtがあるディレクトリを指定しています。 buildディレクトリの中にMakefileなどのプロジェクトファイルとその他の必要なファイルが生成されているはずです。


-- The CXX compiler identification is AppleClang 11.0.0.11000033
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/koichi/cpp/cpp-cmake/build

次のコマンドを実行すれば、CMakeが適当なビルドツールを選んでビルドを実行させてくれます。(実行ファイルを作成するのに、makeコマンドを用いて実行することもできます。)


build $ cmake --build .

.の部分はConfigureとGenerateを実行したフォルダつまりbuildフォルダを指定しています。このコマンドの入力後

Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/hello.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

となって、ビルドが完成します。生成されたファイルを見てみると


build $ ls
CMakeCache.txt		Makefile		main
CMakeFiles		cmake_install.cmake

実行ファイルのmain、CMakeFilesディレクトリ、および、Makefileファイルなどが作成されています。


build $ ./main
Hello, World!

となってmainファイルが実行できます。ソースファイルが複数になるケースでは、add_executableの記述内で、hello.cppの後にそのファイル名を追加することになります。ヘッダの依存関係はcmakeが勝手に解決してくれます。



このページの先頭に戻る

Python Tutorialsのページ
トップ・ページに行く