第46回 補足 – 定数定義

今回から補足知識を説明していきます。

目次

補足記事

この基礎編パート1では、プログラミングに必要な最低限の知識を習得してきました。

ただ、他の人が書いたスケッチを見てみると、今までの説明に出てこなかったコードで書かれている場合があります。

それらすべてを隅々まで理解するには、さらに多くの知識が必要になります。

そこで、Arduinoのスケッチでよく見かけるコードについて、何回かの記事に分けて補足解説します。

#defineによる定数定義(復習)

第15回の記事で、スケッチの中に出てくる定数を#defineを使って定義する方法を解説しました。

例えば、10番端子に接続している緑色LEDを出力制御に設定して点灯する場合、#defineを使わないで書くと次のようなスケッチになります。

pinMode(10, OUTPUT);     // 10番端子を出力制御にする
digitalWrite(10, HIGH);  // 10番端子の内部スイッチをONにする

でもこのようなコードを書いてしまうと、LEDの接続端子を変更した場合、端子番号の「10」を何ヵ所も変更する手間がかかってしまいますし、間違える可能性もありますよね。


そこで、次のようにLEDを接続している端子番号を#defineで定義すると、変更しやすくなりますし、スケッチも読みやすくなる、というメリットがありました。

#define GREEN_LED 10  // 緑色LEDの接続端子番号を定義

pinMode(GREEN_LED, OUTPUT);     // 緑色LEDの接続端子を出力制御にする
digitalWrite(GREEN_LED, HIGH);  // 緑色LEDをONにする

上のスケッチではコメントを書いていますが、コメントがなくても何をしているのかなんとなく想像つきますよね。


ところで、このように定数を定義する方法は他にもあります。

そこで、Arduinoのサンプルスケッチなどでよく見かける次の2通りの定数数定義の方法ご紹介します。

#define以外の定数定義の方法
  • constによる定数定義
  • 変数による定数定義

なんのこっちゃ?って感じですので、それぞれ詳しく見ていきましょう!

constによる定数定義

変数宣言?

Arduinoのサンプルスケッチを見ると、定数定義として次のような書き方がされているケースがあります。

const int GREEN_LED = 10;  // 緑色LEDの接続端子番号を定義

pinMode(GREEN_LED, OUTPUT);     // 緑色LEDの接続端子を出力制御にする
digitalWrite(GREEN_LED, HIGH);  // 緑色LEDをONにする

1行目は変数宣言のように見えますが、変数宣言の前にconstと書かれていて、意味がよくわからないですよね。

でもこのスケッチは先ほどの緑色LED制御のスケッチと同じ意味になっているんです!

先ほどのスケッチでは#define GREEN_LED 10と書いて、GREEN_LEDは10の意味としていました。このスケッチも同様にGREEN_LEDは10の意味として解釈されます。

でもこのスケッチは1行目が謎ですよね。そこで、このスケッチの意味を理解していきましょう。


最初に、1行目のconstがないスケッチを考えてみます。

int GREEN_LED = 10;  // 緑色LEDの接続端子番号を定義

pinMode(GREEN_LED, OUTPUT);     // 緑色LEDの接続端子を出力制御にする
digitalWrite(GREEN_LED, HIGH);  // 緑色LEDをONにする

このスケッチの1行目では、int型のGREEN_LEDという変数を宣言して10で初期化しています(10を代入しています)。

3行目と4行目では、このGREEN_LEDを引数の端子名に使用しています。GREEN_LEDは10が代入されていますので、pinModedigitalWriteの端子名に「10」が指定されるわけです。

でもこの書き方の場合、GREEN_LED変数ですが、この変数を変更することはありませんよね。#define GREEN_LED 10 と同様に、GREEN_LEDに何かを代入して変更することはありません。

でも実際にはint GREEN_LED = 10;と書いているわけですから、どこからどう見てもGREEN_LEDは変数です。

初めてこのスケッチを見た人はGREEN_LEDは変数だからどこかで変更することがあるのかな?などと思ってしまいます。


そこで、このように変数として宣言した場合でも、この変数は定数でスケッチの中では変更することはありませんよ、という書き方があります。

それがconstです。

const int GREEN_LED = 10;

このように、変数宣言の前にconstと書くと、GREEN_LEDは変数ではなく定数として扱ってください、という意味になります。

例えばconst付きで宣言した変数を、次のように変更しようとするとエラーになります。

const int GREEN_LED = 10;  // 定数

GREEN_LED = 8;  // 定数を変更しようとしているのでエラーになる!

Arduinoのサンプルスケッチや、他の人が書いたコードなどをみると、#defineではなくこのようにconstを使用しているケースもありますので、ぜひ頭の片隅に入れておいていただければと思います。


なお、上の例では#defineと同様に定数名を大文字のGREEN_LEDとしましたが、変数と同様に次ように小文字で書く場合も多く見られます。(個人的な印象としては小文字で書くケースが多いように思います)

const int green_led = 10;  // 緑色LEDの接続端子番号を定義

pinMode(green_led, OUTPUT);     // 緑色LEDの接続端子を出力制御にする
digitalWrite(green_led, HIGH);  // 緑色LEDをONにする

constを使うメリット

結局、const#defineと同様の働きをするため、#defineとの違いがよくわかりませんよね。

constと#defineの大きな違いは「constの場合、データの型がわかる」という点があります。

例えば、タイマーの時間を整数で定義するためにTIMER_TIMEという名前で定義したい場合、constと#defineは次のようになります。

const int TIMER_TIME = 10;   // constを使った定数の場合

#define TIMER_TIME 10  // #defineを使った定数の場合

この2つの書き方の大きな違いは、constではTIMER_TIME整数であることが明確、という点です。

#defineTIMER_TIMEはどのようなデータ型なのかよくわかりません。例えば次のように小数を定義することもできてしまいます。

#define  GREEN_LED  10.5

constの場合は、TIMER_TIMEint型で宣言されているので、次のように定義するのはおかしい、と気づきますよね。

const int GREEN_LED = 10.5;  // int型変数なので、この行だけでおかしいことがわかる

このように、定数を定義するときにデータ型が明確になっているconstが使われることがよくあります。

スケッチ例などでconstを見かけた場合、このように背景があるんだな、と思っていただければと思います。

変数による定数定義

ここまで、定数を定義するために#defineとconstの2種類をご紹介してきました。

でもArduino IDEのサンプルスケッチをみると、定数を変数として宣言しているケースもあります

ちょっと???ですよね。

そこで、具体的なサンプルスケッチで確認してみます。


Arduino IDEのメニューから「ファイル」▶︎「スケッチ例」▶︎「01.Basics」▶︎「DigitalReadSerial」という名前のスケッチがあります。スケッチは次のようになっています。

/*
  DigitalReadSerial

  Reads a digital input on pin 2, prints the result to the Serial Monitor

  This example code is in the public domain.

  https://www.arduino.cc/en/Tutorial/BuiltInExamples/DigitalReadSerial
*/

// digital pin 2 has a pushbutton attached to it. Give it a name:
int pushButton = 2;

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // make the pushbutton's pin an input:
  pinMode(pushButton, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input pin:
  int buttonState = digitalRead(pushButton);
  // print out the state of the button:
  Serial.println(buttonState);
  delay(1);  // delay in between reads for stability
}

このスケッチの制御内容は、スイッチが接続されている端子の状態をdigitalReadで読み取って(25行目)、その結果をシリアルモニタに表示する(27行目)、という内容です。

このスケッチでは、スイッチの接続端子を12行目で定義しています。次のように、pushButtonという変数を宣言して2で初期化しています。

int pushButton = 2;

この行はconstが付いていないので変数になってしまっています。でも実際には接続端子の定義としていますので、スケッチの中ではpushButtonは変更することはありません。


このようにスケッチによっては、定数を変数として宣言するケースも見られます。

ただ、このようなケースの場合、Arduino IDEは賢く振舞います。

Arduino IDEは、12行目でpushButtonという変数が宣言されているものの、スケッチの中ではpushButtonは変更されいないので定数として認識します

本来でしたらint型のpushButtonはグローバル変数として宣言していますので、メモリにpushButton保存領域が確保されメモリが消費されてしまいます

でもArduino IDEは、pushButton変数として用意する必要がないので、メモリには保存領域を用意しない、という処理をします

定数定義まとめ

Arduinoのスケッチで定数を定義する場合、次の3種類があります。サンプルスケッチを読むときなど注意していただければと思います。

定数定義の方法
  • #defineによる定義
  • constによる定義
  • 変数による定義

更新履歴

日付内容
2019.12.28新規投稿
2021.8.27新サイトデザイン対応
2025.1.15説明内容を#defineとconstに変更
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次