情報処理のWeb教科書―IPA情報処理試験対策のお供に!

C言語―フリーソフトのgccコンパイラでコンパイルして学ぶC言語入門テキスト

トップ プログラミング C言語

Windowsでも使えるフリーソフトのgccコンパイラで学ぶC言語入門用のオリジナルテキストをまとめています。フリーソフトのgccコンパイラのインストール方法や基本文法はもちろんですが、分割コンパイルやヘッダーファイルの作成方法など入門者にとって気になる内容もまとめています。

目次

この記事の目次です。

1. C言語とは

2. gccコンパイラのインストール

3. C言語プログラミング入門(構文)

4. C言語プログラミング基礎(標準ライブラリ)

5. C言語プログラミング中級(gccコンパイラなど)

もっと知識を広げるための参考

更新履歴

1. C言語とは

C言語とは、コンピュータのプログラム言語の1つです。 プログラム言語はプログラミング言語ともいいます。

C言語とはどのようなプログラム言語か

C言語は、1972年に米国AT&T社ベル研究所のD.M.RitchieとB.W.Kernighanにより開発されたプログラム言語です。 OSやミドルウェアなどさまざまなソフトウェアの開発に使われています。

プログラム言語

プログラム言語とは、ソースプログラムの記述ルールのことをいいます。 プログラミング言語とも言います。C言語の他に、アセンブリ、C++、C#、Java、PHP、Python、Rubyなど多数あります。

なお、プログラム言語について詳しくは、詳細のページで解説しています。

詳細

C言語とコンパイラー

ソースプログラムは、コンピュータで実行できるプログラムのもととなる記述です。 C言語で記述したソースプログラムは人間がプログラムを記述するためのもので実際には動かすことはできません。

コンピュータでプログラムを動かすためにはコンピュータ用のコードに変換する必要があります。 変換にはコンパイラという変換プログラムを使用します。

C言語はコンパイラが必要
C言語はコンパイラが必要!

ソースファイルと実行形式ファイル

コンパイラでソースプログラムからコンピュータが実行できるプログラムに変換します。 ソースプログラムを記述したファイルをソースファイルといいます。 そして、ソースファイルをコンパイルしてできた実行可能なファイルのことを実行形式ファイルといいます。

2. gccコンパイラのインストール

前述のとおり、C言語のプログラムはC言語でプログラムを記述したファイル(ソースファイル)を作るだけでは動かすことはできません。 ソースファイルをコンパイラーでコンピュータが実行できる形式のファイルに変換する必要があります。

おすすめのコンパイラはgcc

どのコンパイラがおすすめかと悩みますが、 gccコンパイラは、メジャーなCコンパイラで、WindowsやLinuxなど複数のOSに対応しています。 実務にも使えますし、gccコンパイラを使って学習すると各種OSに対応したプログラムが作れます。 初心者の方がC言語に入門する場合はgccコンパイラがおすすめです。

初心者がC言語に入門する場合はWindows版のgcc

初心者がC言語に入門する場合はコマンドラインで使用するWindows版のgccがおすすめです。 いきなり高度な統合開発環境を使用するとコンパイル、リンクなどの仕組みがわかりにくくなるためです。

MinGWは Minimalist GNU for Windows"の略で、ネイティブのWindowsアプリケーションを開発するために必要な最小限の環境を提供するツールセットがまとめられています。

Windows版のgccのMinGWのインストール

Windows版のgccコンパイラのMinGWのインストール方法についてみていきます。

MinGWのダウンロード

http://www.mingw.org/へアクセスして「Download Installer」をクリックすると、 https://sourceforge.net/projects/mingw/files/latest/download?source=filesに遷移してインストーラのダウンロードが行われます。

MinGWのインストール

ダウンロードしてきたインストーラ「mingw-get-setup.exe」を実行し、そのまま既定値を選んでいって、MinGW Installation Managerのところでmingw32-baseとmingw32-gcc-g++を選択します。 選択したら、画面上部にあるメニューのInstallation>Apply Changesを実行します。

MinGWのインストールの詳細

Windows版のgccコンパイラのMinGWののインストールの詳細です。

「mingw-get-setup.exe」を実行

「mingw-get-setup.exe」を実行し、「Install」をクリックします。

「mingw-get-setup.exe」を実行
「mingw-get-setup.exe」を実行
Step1

特に変更する必要ありません。そのままContinueをクリックします。

「mingw-get-setup.exe」を実行―Step1
「mingw-get-setup.exe」を実行―Step1
Step2

Step2も、そのままContinueをクリックします。

「mingw-get-setup.exe」を実行―Step2
「mingw-get-setup.exe」を実行―Step2
mingw32-baseとmingw32-gcc-g++を選択

mingw32-baseとmingw32-gcc-g++を選択します。

mingw32-baseとmingw32-gcc-g++を選択
mingw32-baseとmingw32-gcc-g++を選択
メニューのInstallation>Apply Changesをクリック

メニューのInstallation>Apply Changesをクリックします。

メニューのInstallation>Apply Changesをクリック
メニューのInstallation>Apply Changesをクリック
Applyをクリック

Applyをクリックします。

Applyをクリック
Applyをクリック
インストール終了

Closeをクリックします。

Closeをクリック
Closeをクリック

環境変数のPATHの設定

インストーラが終了したら、インストールフォルダ以外でツールが使用できるように環境変数のPATHの設定を行います。

MinGWのインストール先のbinフォルダのパスを環境変数のPATHに設定します。 インストール時にインストール先を変更していない場合は「C\MinGW\bin」をシステム環境変数のPATHの値の末尾に「;(セミコロン)」を付けて「;C\MinGW\bin」追加します。

環境変数のPATHの設定の詳細

環境変数のPATHの設定の詳細です。

システムのシステムの詳細を開き、環境変数(N)をクリック

コントロール パネル>すべてのコントロール パネル項目>システムのシステムの詳細を開き、環境変数(N)をクリックします。

システムのシステムの詳細を開き、環境変数(N)をクリック
システムのシステムの詳細を開き、環境変数(N)をクリック

Windows版のgccコンパイラのMinGWのインストールが完了です。

「;C\MinGW\bin」追加

システム環境変数のPATHを選択して編集をクリックし、変数値の末尾に「;(セミコロン)」を付けて「;C\MinGW\bin」追加します。

「;C\MinGW\bin」追加
「;C\MinGW\bin」追加

Linux版のgccのインストール

Linux版のgccのインストール方法についてみていきます。

Debian系

UbuntsなどDebian系はopt-getでインストールできます。

$ sudo apt-get install gcc

CentOSなどRed Hat系

CentOSやFedraなどRed Hat Enterprise Linux系はyumでインストールできます。

$ sudo yum install gcc

参考)Linux

Linuxとは、WindowsやMacと同じOSの1つです。読み方はリナックスです。Linuxとはどのようなものかの説明を簡単にまとめています。 またネタとして使える日本産の軽量ディストリビューションのlinuxbeanの情報、コマンドラインの「$」「#」「cd」「~」記号の意味などの入門者にとってよくわからない点をわかりやすくまとめています。

詳細

参考)gcc

分割コンパイルやユーザ定義のヘッダーファイルの活用などgccコマンドの知識が必要です。 gccコマンドのオプションの知識およびgccコンパイラーの使い方について掘り下げていきます。

詳細

3. C言語プログラミング入門(構文)

C言語のプログラムの書き方から、for文、if文なのど構文、フローチャートの書き方など、C言語プログラミング入門レベルの内容を、 簡単なプログラムなら自由に作成できるレベルを目指して、初歩的なC言語の基本文法についてみていきます。

詳細

4. C言語プログラミング基礎(標準ライブラリ)

標準ライブラリの利用方法についてまとめていきます。

標準ライブラリとは

標準ライブラリとは、通例的に言語の各実装に備えられているライブラリです。 C言語の標準Cライブラリ(ひょうじゅんシーライブラリ)は、C言語の標準規格で定められた、型・マクロ・関数の集合からなるライブラリです。

stdio.h

stdio.h関連の関数について見ていきます。

printf関数

printf関数は、print formattedの略でプリントエフと呼びます。 C言語の標準入出力ヘッダー (stdio.h)で宣言されている関数で、引数で与えられた書式付きの文字列を、環境によって設定された標準出力(stdout)に出力します。

printf関数(書式付出力)に第1引数のみ指定して文字列を出力する方法

stdio.hのprintf関数(書式付出力)に第1引数のみ指定して文字列を出力する方法について説明しています。

サンプルソース

ソースフォルダに以下のサンプルコードを記述したテキストファイルを作成します。

//ファイル名:hello.c

#include <stdio.h>

int main(void) {
	printf("Hello World!!");
	return 0;
}
コンパイル方法

コマンドプロンプトでソースファイルを保存したフォルダに移動しgccコマンドを実行してコンパイルします。

>cd test
>gcc hello.c

実行方法

a.exeというファイルができたフォルダにコマンドプロンプトで移動し、 a.exeとコマンドラインに入力すると「Hello World!!」と出力されます。

>a.exe
Hello World!!

printf関数(書式付出力)で改行を追加する方法

stdio.hのprintf関数(書式付出力)で改行を追加する方法について説明しています。

printf関数で「\n」を追加することで文字列に改行が追加できます。。

サンプルソース

ソースフォルダに以下のサンプルコードを記述したテキストファイルを作成します。

//ファイル名:hello.c

#include <stdio.h>

int main(void) {
	printf("Hello World!!\nHello World!!");
	return 0;
}
コンパイル方法

コマンドプロンプトでソースファイルを保存したフォルダに移動しgccコマンドを実行してコンパイルします。

>cd test
>gcc hello.c

実行方法

a.exeというファイルができたフォルダにコマンドプロンプトで移動し、 a.exeとコマンドラインに入力すると「Hello World!!」が改行されて2回出力されます。

>a.exe
Hello World!!
Hello World!!

printf関数(書式付出力)で変換指定子(%c)を使用して文字を出力する方法

stdio.hのprintf関数(書式付出力)で変換指定子(%c)を使用して文字を出力する方法について説明しています。

変換指定子(%c)を使用することで変数の値の文字を出力することができます。

サンプルソース

ソースフォルダに以下のサンプルコードを記述したテキストファイルを作成します。

//ファイル名:hello.c

#include <stdio.h>

int main(void) {
	char c = 'H';
	printf("%c", c);

	c = 'e';
	printf("%c", c);

	c = 'l';
	printf("%c", c);

	c = 'l';
	printf("%c", c);

	c = 'o';
	printf("%c", c);

	c = ' ';
	printf("%c", c);

	c = 'W';
	printf("%c", c);

	c = 'o';
	printf("%c", c);

	c = 'r';
	printf("%c", c);

	c = 'l';
	printf("%c", c);

	c = 'd';
	printf("%c", c);

	c = '!';
	printf("%c", c);

	c = '!';
	printf("%c", c);
	return 0;
}

サンプルコードについて

文字(char)型の値はシングルコーテーション(')で囲んで表現します。

サンプルコードでは、cという文字(char)型の変数に 'H'、'e'、・・・'d'、'!'、'!'という文字を順番に設定(代入)して表示し、「Hello World!!」と出力しています。

printf関数にカンマ区切りで引数を2つしていしており、1つ目に%cを設定し、2つ目の引数で指定した変数cの値が出力されるようにしています。

コンパイル方法

コマンドプロンプトでソースファイルを保存したフォルダに移動しgccコマンドを実行してコンパイルします。

>cd test
>gcc hello.c

実行方法

a.exeというファイルができたフォルダにコマンドプロンプトで移動し、 a.exeとコマンドラインに入力すると「Hello World!!」と出力されます。

>a.exe
Hello World!!

printf関数(書式付出力)で変換指定子(%d)を使用して整数を出力する方法

stdio.hのprintf関数(書式付出力)で変換指定子(%d)を使用して整数を出力する方法について説明しています。

変換指定子(%d)を使用することで変数の値の整数を出力することができます。

サンプルソース

ソースフォルダに以下のサンプルコードを記述したテキストファイルを作成します。

//ファイル名:sample.c

#include <stdio.h>

int main(void) {
	int i = 0;
	printf("%d\n", i);

	i = 1;
	printf("%d\n", i);
	return 0;
}

サンプルコードについて

サンプルコードでは、iという整数(int)型の変数に0、1という数を順番に設定(代入)して出力しています。

printf関数にカンマ区切りで引数を2つしていしており、1つ目に%dを設定し、2つ目の引数で指定した変数iの値が出力されるようにしています。

コンパイル方法

コマンドプロンプトでソースファイルを保存したフォルダに移動しgccコマンドを実行してコンパイルします。

>cd test
>gcc sample.c

実行方法

a.exeというファイルができたフォルダにコマンドプロンプトで移動し、 a.exeとコマンドラインに入力すると0と1の数字が改行されて出力されます。

>a.exe
0
1

printf関数(書式付出力)で変換指定子(%s)を使用して文字列を出力する方法

stdio.hのprintf関数(書式付出力)で変換指定子(%s)を使用して文字列を出力する方法について説明しています。

変換指定子(%s)を使用することで変数の値の文字列を出力することができます。

サンプルソース

ソースフォルダに以下のサンプルコードを記述したテキストファイルを作成します。

//ファイル名:hello.c

#include <stdio.h>

int main(void) {
	char message[] = "Hello World!!";
	printf("%s\n", message);
	return 0;
}

サンプルコードについて

サンプルコードでは、messageという文字列(文字の型charの配列を示すため[]を付与)の変数に「Hello World!!」という文字列を初期値として設定(代入という)して変数を宣言しています。

printf関数にカンマ区切りで引数を2つしていしており、1つ目に%sを設定し、2つ目の引数で指定した変数messageの値が出力されるようにしています。

コンパイル方法

コマンドプロンプトでソースファイルを保存したフォルダに移動しgccコマンドを実行してコンパイルします。

>cd test
>gcc hello.c

実行方法

a.exeというファイルができたフォルダにコマンドプロンプトで移動し、 a.exeとコマンドラインに入力すると「Hello World!!」と出力されます。

>a.exe
Hello World!!

fgets関数

C言語のfgets関数は、ファイルの内容を1行読み取る機能がある関数です。

早速、C言語のfgets関数の使い方を見ていきます。

fgets関数のプロトタイプ宣言

fgets関数のプロトタイプ宣言は以下です。

char *fgets(const char *s, int size, FILE *stream);

ファイルポインタ(FILE *stream)で表されるファイルから1行分をバッファ(char *s)へ読み込みます。 ここでの1行は改行がでてくるまでで、バッファには改行も含まれます。

fgets関数の使い方の例

C言語のサンプルコード例を見ながら、具体的にfgets関数の使い方を見ていきます。

サンプル

以下はfgets関数を用いたC言語のサンプルコードです。

#include <stdio.h>

int main(void) {
    FILE *fp;
    char s[15];
    fp = fopen("readfile.txt", "r");

    if (fp == NULL) {
        printf("file open errer.\n");
        return 1;
    }
    fgets(s, 15, fp);
    fclose(fp);
    printf("%s", s);
    return 0;
}

サンプルソースのコンパイル

サンプルコードをコンパイラでコンパイルして実行してみます。

gcc sample.c
実行

たとえば、以下のように改行を含む文字列をreadfile.txtに記述して置きます。

Hello World!!

実行してみると改行を含む文字列が表示されます。

a.exe
Hello World!!

fputs関数

標準Cライブラリ関数のfputs(stdio.h)について見ていきます。

fputs関数を使用することでファイルに1行出力することができます。

サンプルコード(sample.c)
#include <stdio.h>

int main(void) {
    FILE *fp;
    fp = fopen("outputfile.txt", "w");

    if (fp == NULL) {
        printf("file open errer.\n");
        return 1;
    }

    fputs("Hello World!!\n", fp);
    fclose(fp);
    return 0;
}

コンパイル

gccを使用してコンパイルする例を示します。

gcc sample.c
実行
a.exe

実行すると「outputfile.txt」というファイルができます。 ファイルの中には「Hello World!!」と出力されます。

string.h

string.h関連の関数について見ていきます。

文字列関連ライブラリ(string.h)

文字列はとてもよく使用されるものの、C言語では文字を1つずつ文字配列中に格納していく必要があり面倒です。 このため、文字列の操作を行うためのさまざまな関数が用意されています。 標準ライブラリのstringにはこの文字列操作に関する関数があります。

strcpy関数

strcpy関数について解説していきます。

書式

strcpy関数の書式は以下です。

char *strcpy(char *s1, const char *s2);

文字型配列 *s1 に文字列 *s2 を '\0' までコピーします。 '\0' もコピーするので s1 はその分も考えて大きさを宣言しておかなければなりません。 もし、s1 と s2 が重なっている場合には動作は未定義となります。

サンプル
#include <stdio.h>
#include <string.h>

int main() {
      char str[20];
      strcpy(str, "Hello World!\n");
      printf(str);
}
コンパイル

gccを使用してコンパイルする例を示します。

gcc sample.c
実行
a.exe

実行すると「Hello World!!」と出力されます。

5. C言語プログラミング中級(gccコンパイラなど)

gccコンパイラなど、C言語プログラミングの中級レベルの内容をまとめていきます。

Windows API

Windows APIを使用すれば、C言語でWindowsプログラミングが行えます。

メッセージボックスの表示

Windows APIを使用してメッセージボックスを表示する例です。

サンプルソース(sample.c)

ソースフォルダに以下のサンプルコードを記述したテキストファイルを作成します。

#include<windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow) {
    MessageBox(NULL, TEXT("メッセージ"),TEXT("タイトル"), MB_OK);
    return 0;
}
コンパイル方法

コマンドプロンプトでソースファイルを保存したフォルダに移動しgccコマンドを実行してコンパイルします。

>cd test
>gcc sample.c

実行方法

a.exeというファイルができたフォルダにコマンドプロンプトで移動し、 a.exeとコマンドラインに入力もしくはエクスプローラからマウスでダブルクリックするとメッセージボックスが表示されます。

C言語で作成したメッセージボックスの表示例
C言語で作成したメッセージボックスの表示例

gcc

分割コンパイルやユーザ定義のヘッダーファイルの活用などgccコマンドの知識が必要です。 gccコマンドのオプションの知識およびgccコンパイラーの使い方について掘り下げていきます。

詳細

gdb

gdbは、デバックツールの1つで、ブレークポイントというコードの位置を設定し、そこで一時停止し、変数の値を確認するなどプログラマの顕微鏡みたいなツールです。 gdbを使用しながらC言語やコンピュータの理解を深めていきたいと思います。

gdbの簡単な使い方

基礎知識を補いながら、gdbの簡単な使い方を説明していきます。

プロセッサ

プロセッサは、コンピュータの中でプログラムに記述された命令セットを実行するためのハードウェアです。演算装置、命令や情報を格納するレジスタ、周辺回路などから構成されます。 プロセッサはCPUやGPUなどの総称で、システムの中心となるものをCPU、グラフィックボードで使われるプロセッサをGPUといいます。 プロセッサのアーキテクチャにはx86などがあります。

x86

かなり昔に、Intelが8086というCPUを開発・製造しました。 そのファミリ製品として80286、80386、80486・・・と改良版が開発されてきました。 これら製品の86の前の数字をxとしてファミリ製品を呼ぶようになりました。X86はIntelのCPUの製品ファミリを指す言葉が生まれ、そのプロセッサのアーキテクチャがX86アーキテクチャと呼ばれます。 このアーキテクチャはAMDなどIntel以外でも採用され、今日に至ります。

レジスタ

レジスタとは、プロセッサなどが内蔵する記憶回路です。 x86プロセッサには、プロセッサ用の内部変数ともいうべきレジスタが複数搭載されています。

サンプルソース(hello.c)

Hello World!!を10回表示するプログラムをGDBで見ていきたいと思います。サンプルソースは以下です。

#include <stdio.h>
int main() {
        int i;
        for (i = 0; i < 10; i++) {
                printf("Hello world!!\n");
        }
        return 0;
}
gdbの使用例

gdbの使用例です。環境はCentOS7で仮想環境で起動しています。

# gcc hello.c
# gdb -q ./a.out
Reading symbols from /root/work/a.out...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x400521
(gdb) run
Starting program: /root/work/./a.out

Breakpoint 1, 0x0000000000400521 in main ()
Missing separate debuginfos, use: debuginfo-install glibc-2.17-260.el7_6.6.x86_64
(gdb) info registers
rax            0x40051d 4195613
rbx            0x0      0
rcx            0x400550 4195664
rdx            0x7fffffffe5c8   140737488348616
rsi            0x7fffffffe5b8   140737488348600
rdi            0x1      1
rbp            0x7fffffffe4d0   0x7fffffffe4d0
rsp            0x7fffffffe4d0   0x7fffffffe4d0
r8             0x7ffff7dd5e80   140737351868032
r9             0x0      0
r10            0x7fffffffe020   140737488347168
r11            0x7ffff7a303a0   140737348043680
r12            0x400430 4195376
r13            0x7fffffffe5b0   140737488348592
r14            0x0      0
r15            0x0      0
rip            0x400521 0x400521 <main+4>
eflags         0x246    [ PF ZF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) quit
A debugging session is active.

        Inferior 1 [process 1727] will be killed.

Quit anyway? (y or n) y
gdbのコマンド

上記例ではgdbのqオプションで実行形式ファイルのa.outを起動しています。 その後、breakでmain関数にブレークポイントを設定して、runでプログラムをブレークポイントまで実行し、 その後、info registersでブレークポイントのところではレジスタの状態を表示し、quitで終了しています。

表示されたレジスタ

表示されたレジスタについて解説します。

主に一時変数に用いられる汎用レジスタ
主にポインタやインデックスに用いられる汎用レジスタ
実行されようとしている現在の命令が格納されているアドレス
比較演算やメモリのセグメント化など

gdbでの逆アセンブリ結果の表示方法

今度は逆アセンブリ結果を表示してみます。

サンプルソース(hello.c)

ここでもHello World!!を10回表示するプログラムをGDBで見ていきたいと思います。サンプルソースは以下です。

#include <stdio.h>
int main() {
        int i;
        for (i = 0; i < 10; i++) {
                printf("Hello world!!\n");
        }
        return 0;
}
gdbの使用例

gdbの使用例です。環境はCentOS7で仮想環境で起動しています。 gccはgオプションでデバック情報を付加してコンパイルしています。

# gcc -g hello.c
# gdb -q ./a.out
Reading symbols from /root/work/a.out...done.
(gdb) list
1       #include <stdio.h>
2       int main() {
3               int i;
4               for (i = 0; i < 10; i++) {
5                       printf("Hello world!!\n");
6               }
7               return 0;
8       }
9
(gdb) set disassembly-flavor intel
(gdb) disassemble main
Dump of assembler code for function main:
   0x000000000040051d <+0>:     push   rbp
   0x000000000040051e <+1>:     mov    rbp,rsp
   0x0000000000400521 <+4>:     sub    rsp,0x10
   0x0000000000400525 <+8>:     mov    DWORD PTR [rbp-0x4],0x0
   0x000000000040052c <+15>:    jmp    0x40053c <main+31>
   0x000000000040052e <+17>:    mov    edi,0x4005e0
   0x0000000000400533 <+22>:    call   0x400400 <puts@plt>
   0x0000000000400538 <+27>:    add    DWORD PTR [rbp-0x4],0x1
   0x000000000040053c <+31>:    cmp    DWORD PTR [rbp-0x4],0x9
   0x0000000000400540 <+35>:    jle    0x40052e <main+17>
   0x0000000000400542 <+37>:    mov    eax,0x0
   0x0000000000400547 <+42>:    leave
   0x0000000000400548 <+43>:    ret
End of assembler dump.
(gdb)
gdbのコマンドについて

listは、gccのgオプションで付加したデバック情報を表示します。 set disassembly-flavor intelは、intel形式で表示しています。 disassembleは、逆アセンブリ結果を表示するコマンドです。

簡単に動作について解説すると以下のようになります。

  1. 「push rbp」でrbp(ベースポインタ)をスタックに設定して
  2. 「mov rbp, rsp」でrsp(スタックポインタ)からrbpに値を移した後、
  3. 「sub rsp,0x10」でrspから0x10引いた値をrspに格納し、
  4. 「mov DWORD PTR [rbp-0x4],0x0」でrbpの値から4引いたところからのアドレス、4バイトに0x0の値を代入し、
  5. 「jmp 0x40053c <main+31>」で0x40053c <main+31>にジャンプして、
  6. 「cmp DWORD PTR [rbp-0x4],0x9」「jle 0x40052e <main+17>」でDWORD PTR [rbp-0x4],0x9が9以下の場合は 0x40052e <main+17>にジャンプ、
  7. 「mov edi,0x4005e0」で0x4005e0(「Hello World!!」という文字列があるアドレス)からedi※に値を移す、
  8. あとは、callでこれを引数にして出力して、addで変数iの値をプラス1して・・を繰り返して最後にeaxに0を設定してleave、retと処理を終了

※ediは、ディスとネーションポインタ、メモリのアドレスを覚えておくのに使います。

アセンブリ言語

アセンブリ言語について補足していきます。

アセンブリ言語とC言語

gdbで、レジスタの値を表示すると16進表記のバイト群が表示されます。 これがx86プロセッサ向けのマシン語命令です。

16進数値で表示されていますが、CPU上では2進数の0と1の羅列として扱われます。 コンピュータが誕生したころは、この0と1の羅列でプログラミングが行われていたわけですが、見やすくないのでアセンブリ言語が登場しました。 アセンブリ言語は、マシン語の命令を覚えやすい略語(ニーモニック)に置き換えただけのものです。 その後さらにわかりやすくしたC言語などの言語が登場しました。

アセンブリ言語の書式

アセンブリ言語の命令の書式は以下のようにシンプルです。

命令語 <操作の対象>, <参照元>

操作の対象と参照元は、レジスタやメモリアドレス、値のいずれかを指定します。命令語はmovやsubなどのニーモニックと意味が分かりやすくした単語が使われます。

push

pushは、スタックにデータを格納する命令です。

push rbp

push rbp命令は、関数の最初に必ず書かれます。rbpはベースポインタです。 rbpは、簡単にいうと「今実行中の関数が使用しているスタック領域の底」です。底だからベースです。

mov

movは、参照元から操作の対象に向けたデータの移送の命令です。

mov    rbp,rsp

実行例のmovの命令では、rspレジスタからrbpレジスタに値を移送する命令になります。

rspはスタックポインタ、rbpはベースポインタで、主にポインタやインデックスに用いられる汎用レジスタです。

sub

subは格納先から読込元を引いて(減算)、結果を格納先に格納します。

 sub <格納先>, <読込元>

以下の例の場合、rsp(スタックポインタ)から0x10を引いて(減算)、結果をrspに格納しています。

sub    rsp,0x10
DWORD PTR[]

DWORDは4バイトのことです。主レジスタ、ポインタレジスタにアドレスを入れると、DWORD PTR[rbp] のようにして参照できます。

以下の例の場合、rbp(ベースポインタ)の値から4引いた値をアドレスとして用い、そのアドレスから開始している4バイトの値として、0x0を代入するという命令になります。

mov    DWORD PTR [rbp-0x4],0x0
jmp

jmpは<操作の対象>へジャンプさせる命令です。

 jump <操作の対象>

以下の例の場合、0x40053c <main+31>へジャンプする処理になります。

jmp    0x40053c <main+31>
cmp、jle

cmpは比較で、jleは「直前の比較結果が等しいか、それ未満である場合に分岐する」という命令です。

以下の場合、DWORD PTR [rbp-0x4]が0x9以下の場合、 0x40052e <main+17>にジャンプするという命令になります。

    cmp    DWORD PTR [rbp-0x4],0x9
    jle    0x40052e <main+17>

もっと知識を広げるための参考

更新履歴

戻る

スポンサーリンク

情報処理の知識体系

プログラミング

各試験の問題と解説

ランダム出題・採点アプリ

スポンサーリンク