条件文

条件文

前にbit演算のところでAND演算とかOR演算とかやったと思いますが、それをbit単位でなく、変数単位でやるのが条件文です。
条件文の演算結果は真ならば1、偽であれば0となります。例を見てみましょう。

int a = 10;
int tmp = (5 == a);//0になる

条件文は多くの場合大小比較や同値比較と同時に用いられるので、その演算子をまとめておきましょう。

演算子 意味
== 等しい
!= 等しくない
<= (左は)(右)以下である
>= (右は)(左)以下である
< (左は)(右)より小さい
> (左は)(右)より大きい

これに加えてAND,OR,NOT演算子があります

演算子 意味
&& かつ(AND)
|| または(OR)
! 否定(NOT)

if文

条件式をそれ単体で使うことは、そこまで多くなく、if文やこの後紹介するwhile,for,do-while文と共に用いられます。

if文はプログラムを組む上で無くてはならないものです。例を見てみましょう。

if (条件式)
	/* 条件式が真の時 */;
else
	/* 条件式が偽の時 */;

この書き方だと処理が一行しか書けません。複数行書くときは{}を使います。
気をつけて欲しいのですが、{}がなくともブロックがあります。その場合は次の;までがブロックとなります。

ところで言うまでもないですが、else節はなくても構いません。

int first_number, second_number, third_number;
int max_number, center_number, min_number;

if (first_number > second_number) { // 1番目の数と2番めの数を比較
	max_number = first_number;
	center_number = second_number;
} else {
	max_number = second_number;
	center_number = first_number;
} if (third_number > max_number) { // 3番めの数と上で出した「1番目の数と2番めの数」の大きい方と比較
	min_number = center_number;
	center_number = max_number;
	max_number = third_number;
} else if (third_number > center_number) { // 3番めの数と上で出した「1番目の数と2番めの数」の小さい方と比較
	min_number = center_number;
	center_number = third_number;
} else { // 3番目の数が最小の時
	min_number = third_number;
}

このようにif文 else if のように連ねて書くことも可能です。

if (a == 5)
	int x = 7;
else
	x = 6; // これはだめ

そもそもif文の中で変数を宣言しないようにしましょう。変数を宣言したい、そう思ったら、直ちにその部分を関数化しましょう。

コーディングの作法

if文では、else節に正常な動作を書くと、多くの場合ですっきり書けます。

if (条件文) {
	// エラー処理
} else {
	// 正常動作
}

大切なのが、正常な動作の時の流れがもっとも簡潔であるように書くことです。

また、条件式を書く上での注意ですが、同値比較(==)は「=」が2つですが、ついうっかり1つにしてしまいがちです。そこで、このように書くようにしましょう

if (5 == a)//正しい書き方
if (a == 5)//これも正しい書き方
if (5 = a)//これはコンパイルエラー
if (a = 5)//これはコンパイルエラーにならない、aに代入した後のaが0か否かが判別される

constがついた変数や、数値、マクロで定義された値を左側、変数を右側に持っていくようにすることがあります。
こうすることで、書き間違えた時にコンパイルエラーになります。(変更不可能なものに代入しようとしています、など)

エラー処理等、明確に実行文が1行しかない、と言える時を除き、原則{}はつけましょう。あとで文が増えた時に付け忘れるのを防ぐことができます。

3項演算子

if文とは一味ちがう書き方です。見てみましょう。

const int hoge = 17;
const int isEven = (hoge % 2) ? 1324 : 2432;
const int hoge = 17;
int isEven;

if (hoge % 2)
	isEven = 1324;
else
	isEven = 2432;

if文を使って書くより簡単ですし(スコープの問題がない)、代入する変数にconstが付けられます(ワタシ的にはここが美味しい)

この書きかたですが、「一行で」かけるので、後に説明するプリプロセッサマクロでしばしば用いられます。
・・・って私は教わったんだけど、マクロにして使ったことってないなぁ。それくらいならinline関数にしちゃうし。

switch文

if文が高級な条件分岐文とするならば、switch文は低級な条件分岐文といえますが、最大のメリットは、一度の条件式で複数の分岐が作れることです。

char time_when;

switch (time_when) {
	case 'a':
		puts("朝");
		break;

	case 'b':
		puts("昼");
		break;

	case 'c':
		puts("夜");
		break;

	default:
		break;
}

switch文には必ず「default:」を書きましょう。
「case 'c':」とかは「ラベル」といいます。後述するgoto文にも登場するので頭の片隅においておいてください。
「break;」はswitch文を抜け出すために用います。もし、6行目の「break;」がなかった場合、5行目を実行した後8行目を実行します。つまり必ずしもbreakは必須ではありません。
switch文を「低級な条件分岐文」と表現したのは、コンパイラの最適化段階の表現に近いからです。

このswitch文、あとで出てくる列挙型(enum)とものすごく相性がいいです。#defineをわんさか書こうとしているそこのアナタ、enumを使いましょう。

enum型(列挙型)

enum型とは列挙型と呼ばれており、switch文と相性がいいんです。

enum status {
	STATE_TITLE,
	STATE_MAIN,
	STATE_END,
};

ここでstatusはタグ名と言います。タグ名を除いた";"の前まで全体が型となります。enumはtypedefして初めて真価を発揮します。

typedef enum {
STATE_TITLE,
STATE_MAIN,
STATE_END,
} status_t;

typedefするときはタグ名は省略してもいいです。なお、「STATE_ENDのあとになんで","が置けるんだ?」と思ったあなた、よく勉強しています。enumに関しては書けるんです(C89からだっけ・・・?)

実際に例を見ていきましょう

#include "DxLib.h"
#include <stdio.h>
typedef enum {
	STATE_TITLE,
	STATE_MAIN,
	STATE_END,
} status_t;

status_t title()
{
	//タイトルを描画
	//クリック押されたら
	return STATE_END;
}

status_t gameMain()
{
	//ゲーム処理
	//ゲーム終了したら
	return STATE_END;
}

status_t ending(){
	//リザルト画面描画
	//クリック押されたら
	return STATE_MAIN;
}

int main()
{
	if(DxLib_Init() == -1)
		return -1;

	status_t function_status = STATE_TITLE;

	//function 'CheckHitKey' is DxLibrary's function.
	while (CheckHitKey(KEY_INPUT_ESCAPE)) {
		switch (function_status) {
			case STATE_TITLE:
				function_status = title();
				break;

			case STATE_MAIN:
				function_status = gameMain();
				break;

			case STATE_END:
				function_status = ending();
				break;

			default:
				return -1; // エラー
		}
	}

	DxLib_End();
	return 0;
}

このようにゲームなど状態を管理するときに非常に便利です。
まあ、戻り値にするよりポインターか参照(いずれも後述)を使って引数経由でやったほうがいい気もするけど、ケース・バイ・ケースなので。
ていうか教えてないし。

bool型と_Bool型

真偽値はブール、ブーリアンなどと呼ばれ、C言語にはC99で専用の型が導入されました。 stdbool.hをincldueすることによりその型をbool型として使えます。

/*
 * ISO C Standard:  7.16  Boolean type and values  <stdbool.h>
 */

#ifndef _STDBOOL_H
#define _STDBOOL_H

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

/* Supporting <stdbool.h> in C++ is a GCC extension.  */
#define _Bool   bool
#define bool    bool
#define false   false
#define true    true

#endif /* __cplusplus */

/* Signal that all the definitions are present.  */
#define __bool_true_false_are_defined   1

#endif  /* stdbool.h */

C99のbool型は_Bool型をマクロを使って実装しています(マクロが何かは後ほど)。
実際に使い方を見ましょう。

#include <stdbool.h>

int main()
{
	//前略
	bool no_first_skip = true;
	bool no_dct_decimate = false;
	//後略

	return 0;
}

C99のbool型は、真と偽はtrueとfalseに対応し、int型に変換すると1と0になります。それ以外の値を入れられることは保証されていません。