#5 C言語のキホン➁【もっと!後輩たちのためのEV3rt講座】

# 目次

| 章 | タイトル | 内容 |
| :-: | :-: | :-: |
| 1 | [はじめに](#1-はじめに) | 今回やることの説明 |
| 2 | [if文の使い方](#2-if文の使い方) | if文を使った分岐について説明 |
| 3 | [関係演算子](#3-関係演算子) | 条件式を書くための関係演算子について説明 |
| 4 | [switch文の使い方](#4-switch文の使い方) | switch文を使った分岐について説明 |
| 5 | [for文の使い方](#5-for文の使い方) | for文を使ったループについて説明 |
| 6 | [while文の使い方](#6-while文の使い方) | while文を使ったループについて説明 |
| 7 | [待機について](#7-待機について) | 待機処理の仕方について説明 |
| 8 | [まとめ](#8-まとめ) | 今回のまとめ |

# 1. はじめに

前回はC言語のキホン➀として、演算子・変数・配列・関数について簡単に記しました。
今回も同じくC言語のキホン➁として、「分岐」や「ループ」といった制御構文の使い方について説明していきたいと思います。

前回同様、EV3rtで開発する上での最低限の部分のみ記しますので、詳しい文法等はC言語の書籍やサイトを参考にしてください。

## 参考書籍

[新・明解C言語 入門編 第2版 単行本](https://amzn.asia/d/dP2I1o8)

[Cの絵本 第2版 C言語が好きになる新しい9つの扉](https://amzn.asia/d/6snZZj8)

## 参考サイト

[C言語入門 | Let'sプログラミング](https://www.javadrive.jp/cstart/)

[苦しんで覚えるＣ言語](https://9cguide.appspot.com/index.html)

# 2. if文の使い方

今回はまず、「if文」の使い方から説明していきます。

EV3ソフトウェアで言うところの「スイッチ」ですね。

![EV3soft_if1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/cf410a2a-4fd8-8b60-f2d6-7289951fe67a.png)

if文は **「条件分岐」** と呼ばれる制御構文の一つです。
ある「条件」に対してその条件を **「満たしている」か「満たしていない」** かでプログラムを分岐するということです。

例えば以下の例、ポート1に接続されたタッチセンサが「押されている」か「押されていない」かで、変数に代入する値を変えています。

![EV3soft_if2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/04e4f32e-48d5-c1b4-e7f1-073edff5b621.png)

これを、C言語で表現してみましょう。

```c
if(ev3_touch_sensor_is_pressed(EV3_PORT_1)){
  a = 1;
}
else{
  a = 0;
}
```

1行目の`if`の後にカッコ`(` `)`がありますが、この中に **「条件式」** を書きます。
今回は『ポート1に接続されたタッチセンサが「押されている」か「押されていない」か』が条件式ですので、これをプログラムで記述します。
今後のセンサの回で紹介しますが、`ev3_touch_sensor_is_pressed()`という関数でタッチセンサーが押されているか否かを返してくれます。
押されている場合は戻り値として **`True`** が、押されていない場合は **`False`** が返ってきます。

この`True`(真)と`False`(偽)が条件分岐において非常に重要なわけですが、if文ではこの条件式が`True`(真)であった場合、`if`の直後の中カッコ`{` `}` の中身を実行します。
一方、`False`(偽)であった場合、`if`の直後は実行しません。

上記の例では`if`の後に`else`とそれに付随する中カッコ`{` `}`があります。
この場合、条件式が`False`(偽)であった場合は`else`の直後の中カッコ`{` `}` の中身を実行します。

尚、elseの部分は必要なければ省略することも出来ます。
例えば以下のようなプログラムを表現するとき。

![EV3soft_if3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/0d3c4bb3-7712-c55c-d56e-9aca0813d816.png)

```c
a = 0;

if(ev3_touch_sensor_is_pressed(EV3_PORT_1)){
  b = 1;
}

a = 1;
```

else文を使わずとも、これだけで良いわけです。
シンプルで読みやすいプログラムを書くためにも、必要なコードだけ書くように心がけましょう。

## else ifを使う場合

では、以下のようなプログラムを作りたい時はどうすれば良いでしょうか。

![EV3soft_if4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/ec0ae179-6255-d1c4-e6b5-f7bf636b3de9.png)

例えば、こんな👇プログラムが書けるかと思います。

```c
if(ev3_color_sensor_get_color(EV3_PORT_3)==2){ //青か？
  a = 1;
}
else{
  if(ev3_color_sensor_get_color(EV3_PORT_3)==3){ //緑か？
    a = 2;
  }
  else{
    if(ev3_color_sensor_get_color(EV3_PORT_3)==5){ //赤か？
      a = 3;
    }
  }
}
```

確かにこれでも動作はしますが、elseの中へ中へと入ってしまい、コードが見にくくなってしまいます。
そこで、`else if`文を使いましょう。

```c
if(ev3_color_sensor_get_color(EV3_PORT_3)==2){ //青か？
  a = 1;
}
else if(ev3_color_sensor_get_color(EV3_PORT_3)==3){ //緑か？
  a = 2;
}
else if(ev3_color_sensor_get_color(EV3_PORT_3)==5){ //赤か？
  a = 3;
}
```

`else if`文は、直前の`if`文の条件式が`False`(偽)だった時に実行されます。
上記の例で言えば、一行目の『カラーセンサの値が青か』の判定が`False`だった時に、二行目は実行せず、四行目の『カラーセンサの値が緑か』の判定に移るということになります。

これを用いればコードをシンプルに書くことが出来るので、積極的に利用しましょう。
(もちろん、`else`文同様に省略することもできます。)

# 3. 関係演算子

さて、先ほどの`else if`の説明用のコードで、サラッとこんな👇コードを書いてしまいました。

```c
if(ev3_color_sensor_get_color(EV3_PORT_3)==2){ //青か？
  a = 1;
}
```

これの条件式の中にあるイコール`=`が二つ連なった文字`==`ですが、これは`==`の両隣の値が **「等しいかどうか」** を調べるものです。
こういった文字のことを、「関係演算子」(かんけいえんざんし)といいます。

上記のコードの例の場合、関数`ev3_color_sensor_get_color()`により、カラーセンサの値が戻り値として返ってきます。
その値と、右辺側の値`2`が等しいかを調べて、等しければ`True`(真)を、等しくなければ`False`(偽)を返すということになります。

このような関係演算子はいくつか種類がありますので、EV3ソフトのブロックと比べながら紹介していきます。

![EV3soft_if5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/ca5ea40e-e7d2-1a32-5a85-f30cff20c277.png)

| 演算子 | 記述例 | 意味 | EV3ソフトの値 |
| :-: | :-: | :-: | :-: |
| == | a == b | bがaに等しい | 0 |
| != | a != b | bがaに等しくない | 1 |
| > | a > b | bよりaが大きい | 2 |
| >= | a >= b | bよりaが大きいか等しい | 3 |
| < | a < b | bよりaが小さい | 4 |
| <= | a <= b | bよりaが小さいか等しい | 5 |

[C言語入門 | Let'sプログラミング / 関係演算子 / 関係演算子の種類](https://www.javadrive.jp/cstart/if/index2.html) より引用・追記

例えば以下のようなEV3ソフトでのプログラムをC言語で表現してみます。

![EV3soft_if6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/23ab95ed-c5d2-3cb0-535e-b8a62b522423.png)

```c
if(ev3_color_sensor_get_reflect(EV3_PORT_3)>30){
  a = 1;
}
else{
  a = 2;
}
```

他の演算子についても、上記の例のようにして使うことができるので、是非試してみてください。

# 4. switch文の使い方

if文の章で、`else if`文を使えば複数の条件分岐が書ける事を紹介しましたが、その条件分岐がいくつもあるとき、いちいち`else if`で条件式を書くのも面倒です。
そのような時は、これから紹介する`switch`文を使うことでプログラムを簡潔に書くことが出来ます。

例えば、以下のようなEV3ソフトのブロックを使いたいとします。

![switch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/e7babb18-1d2e-5818-fcdc-2a1b0ce7153e.png)

EV3ソフトにおいても縦に長くなりすぎてしまい、プログラムが億劫になるほどです。

これを`if`文および`else if`文で表現すると、以下のようになります。

```c
if(ev3_color_sensor_get_color(EV3_PORT_3) == 0){
  // カラー値 0 (判定無し) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 1){
  // カラー値 1 (黒) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 2){
  // カラー値 2 (青) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 3){
  // カラー値 3 (緑) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 4){
  // カラー値 4 (黄) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 5){
  // カラー値 5 (赤) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 6){
  // カラー値 6 (白) の時の処理
}
else if(ev3_color_sensor_get_color(EV3_PORT_3) == 7){
  // カラー値 7 (茶) の時の処理
}
```

EV3ソフトでの表現よりは幾分かマシかもしれません。
しかし、条件式のうち変わっているのは**右辺側の値だけ**で、左辺側の長い関数の部分は一切変わっていないわけです。
これを8つも書くのはやはり無駄ですよね。

そこで登場するのが、`switch`文です。
今回のように、条件式の左側が変わらず、右側の値だけが変わっている時に使うことが出来ます。
上記のコードを`switch`文を使って書き直してみます。

```c
switch(ev3_color_sensor_get_color(EV3_PORT_3)){
  case 0:
    // カラー値 0 (判定無し) の時の処理
    break;
  case 1:
    // カラー値 1 (黒) の時の処理
    break;
  case 2:
    // カラー値 2 (青) の時の処理
    break;
  case 3:
    // カラー値 3 (緑) の時の処理
    break;
  case 4:
    // カラー値 4 (黄) の時の処理
    break;
  case 5:
    // カラー値 5 (赤) の時の処理
    break;
  case 6:
    // カラー値 6 (白) の時の処理
    break;
  case 7:
    // カラー値 7 (茶) の時の処理
    break;
  default:
    // どれにも当てはまらなかったときの処理
    break;
}
```

文法としては、`switch`の後の`(` `)`の中に「判定したい値」を書き、値ごとの処理を`case 【値】:`として分岐して書きます。

「判定したい値」が「caseの後の値」と等しいかどうかを、上から順番に判定してきます。
判定した結果`True`(真)だった場合、その`case`の直後のプログラムを実行します。

処理の一番最後には`break;`というコードがあります。
このコードを書くことで、`switch`文全体から抜け出すことが出来ます。
ちなみに`break;`を書かないと、その下にある`case`に対しても条件を満たすかどうか判定してしまいますので、気を付けましょう。

又、一番下に`default:`がありますが、これはどの条件にも当てはまらなかった時に実行されるコードです。
`if`文における`else`の処理と同じような立ち位置ですね。
`default:`に関しては、書かなくてもコンパイルは通るはずですが、思わぬエラーを引き起こす可能性があるので、書くように心がけましょう。
(例えばエラーの処理を行うとか。)

# 5. for文の使い方

ここからは、ループ処理のやり方について説明していきます。
まずはループ構文の代表格である`for`文の使い方についてです。

例えば、以下のようなEV3ソフトのプログラムがあるとします。

![for1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/746a9847-31bb-7adf-2a5d-c2a2908822cb.png)

意味としては、モータを前後に動かす動作を10回繰り返す、というものですね。
これをC言語の`for`文を用いると、以下のように書くことが出来ます。

```c
int i; // カウンタ変数
for(i=0; i<10; i++){
  ev3_motor_rotate(EV3_PORT_D, 360, 50, true);
  ev3_motor_rotate(EV3_PORT_D, -360, 50, true);
}
```

`for`文の`(` `)`の中については、以下の画像のように、左から順に **「初期化式」「条件式」「変化式」** となっています。

![for2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/eeb1b213-8baa-6f76-8f20-38e212e938e2.png)

まず、`for`文を使うには「カウンタ変数」という変数が一つ必要です。
カウントする変数、つまり「今何回目か?」を格納する変数と考えるとわかりやすいでしょう。

上記のコードでは、一行目に「カウンタ変数」としても用いる変数`i`を定義しています。

次に、`for`文の中に入ると一度だけ「初期化式」が実行されます。
ここで、カウンタ変数を一度初期化するわけです。

その次に、「カウンタ変数が条件式を満たしているか」の判定が入ります。
`True`(真)だった場合は、`for`文の中カッコ`{` `}`の中身のコードが実行されます。

中カッコの中のコードが全て実行されたら、最後に「変化式」が実行されます。
ここで、前回紹介した「インクリメント演算子」が用いられています。
意味としては「変数に`1`加算する」でしたね。
これで、ループ回数を数えていくわけです。

「変化式」が実行された後は、再び「条件式」による判定が行われます。
これが`True`(真)である限り、ループが実行されます。

では、上記のコードでのカウンタ変数`i`が`11`になった時ですが、この時「条件式」による判定結果は`False`(偽)になります。
すると、プログラムは`for`文を抜けて、ループが終了します。

以上が`for`文の基本的な使い方です。

# 6. while文の使い方

もう一つ、代表的なループ構文である`while`文を紹介します。

先ほどの`for`文は、「回数を指定する」タイプのループでしたが、`while`文は「条件を満たしている限り続ける」タイプのループです。

例えば、以下のようなEV3ソフトのプログラムがあるとします。

![while1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/7b4a8d18-a15e-9cde-7437-6a5de0f14d28.png)

意味としては「モータを前後に動かす動作を、カラーセンサの反射光の値が50未満である限り繰り返す」というものですね。
これをC言語の`while`文を用いると、以下のように書くことが出来ます。

```c
while(ev3_color_sensor_get_reflect(EV3_PORT_3) < 50){
  ev3_motor_rotate(EV3_PORT_D, 360, 50, true);
  ev3_motor_rotate(EV3_PORT_D, -360, 50, true);
}
```

`while`文の文法としては、`while`の直後のカッコ`(` `)`に条件式を書き、その条件式を満たしている限り、中カッコ`{` `}`内のコードを実行するという形です。

`for`文と`while`文、状況に合う方のループを選んで使うようにしましょう。

# 7. 待機について

今回は最後に **「待機」** の仕方を説明したいと思います。

EV3ソフトで待機をするには以下のブロックを使用していました。

![wait.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/ca57f77f-1f11-6e6d-3296-78d16ff42c88.png)

EV3rtでは、以下のコードにより待機(正確にはタスクのスリープ)を行います。

```c
tslp_tsk(1*1000*1000);
```

`tslp_tsk()`という関数が、EV3rtの核であるTOPPERS/HRP3のタスクスリープ関数となります。
引数にはスリープする時間(=待機する時間)を **マイクロ秒** 単位で指定します。
(※EV3rt β7.3 まではHRP2を使用しているので「ミリ秒」での指定となります。)

「マイクロ秒」というのは、 $10^{-6} = \frac{1}{10^6}$ 秒のことで、0を6個付けると1秒になります。

ちなみに $10^{-3} = \frac{1}{10^3}$ 秒が「ミリ秒」であり、$1/1000$ されるごとに単位の名前が変わります。

従って、上記のコードのように、$1000$ ずつ掛け算をして表現すると分かりやすいかもしれません。

では実践例を見てみましょう。
例えば、以下のEV3ソフトのブロックのように、モータを0.5秒回転させるプログラムがあるとします。

![wait2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/844696bf-13b4-9eb7-54a2-35f683e70f82.png)

これを先ほどのスリープ関数を用いて表すと、以下のようになります。

```c
ev3_motor_set_power(EV3_PORT_D, 50);
tslp_tsk(500*1000);
ev3_motor_stop(EV3_PORT_D, True);
```

これは、モータを動かす関数に「何秒動かす」という命令がないため、始めにパワーをセットする命令を置いています。
その後、0.5秒スリープさせる処理を行っています。

(EV3ソフトに逆翻訳すれば以下👇のような形になります。)

![wait3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/63143f18-1ac4-bb83-ed31-4dfc0beea2de.png)

以上が、待機処理の行い方でした。
ロボットの制御で待機処理は非常に多く使いますので、これは確実に使えるようにしておきましょう。

# 8. まとめ

今回は分岐やループ、待機といった制御構文を紹介してきました。
プログラミングの本質は「アルゴリズム」の構築であり、それに制御構文は欠かせません。
シンプルで読みやすく、そしてバグのないプログラムを組むためにも、それぞれの制御構文をしっかり使いこなせるようになりましょう。

次回はいよいよモータを動かす関数(API)を紹介していきます。

前回: [#4 C言語のキホン➀](https://qiita.com/koushiro/items/18e0c8dde12f3a8e3aad)
次回: [#6 モータを動かそう](https://qiita.com/koushiro/items/629433156aba2a166094)