Arduino 入門
番外編 15
【#define】と【const】
こんにちは管理人のomoroyaです。
arduino 入門 番外編はarduinoの基本的なことを解説している記事です。
本記事は、管理人も使い分けをきちんと理解していない【#define】と【const】について改めて考えてみます。
なぜ、改めて考えるかというとスケッチ(コード)で定数の定義の仕方が本やネットのサンプルスケッチ(コード)によってマチマチだからです。
管理人はプログラマーの専門家というわけではありません。
これまでは、#defineとconstをあまり意識していませんでした。
そこで今回改めて考えることにしました。
変数のスコープとも絡むお話となります。
下記の記事を読んでおくとより理解が深まると考えます。
arduino自身のこと、スケッチ(コード、プログラム)を少しづつ理解して行きましょう。
いやいや、arduinoを早速始めたいんだ!というかたは下記の入門編からお読みください。
Arduino入門編の解説にて使用しているArduinoは互換品です。
互換品とは言え、Arduinoはオープンソースであり複製して販売するのもライセンス的に問題なし。
そのため互換品の品質も悪くなく、それでいて値段は安いです。
正規品本体の値段程度で豊富な部品が多数ついています。
正規品(Arduino UNO R3)の本体単品がほしい方はこちらとなります。
Arduino入門編2では「Arduino UNO R4 Minima」「Arduino UNO R4 WIFI」にて遊ぶため今のところは正規品を使用。(まだ互換品が・・・ほぼない)
定数の定義でよく見かける構文
スケッチ(コード)の中には定数の定義が必ずでできます。
冒頭であったり、setup()のなかだったりと定義します。
そのとき、本やネットによって同じ内容のスケッチ(コード)なのに定義の仕方が異なっていると事が多々あります。
例えば以下などがそうです。
②const int ledpin = 13;
スケッチ(コード)的には、どちらで定義してもコンパイラエラーもでることはありません。
また、上記の後に同じ内容のスケッチ(コード)をかいたとしても同じように動作します。
ここで、ふと思うわけです。
どっちがいいの?
#defineについて
まずは、#defineについて確認していきます。
- #defineはプログラム中の定数に対して名前を付けることができる
- #defineで定義された定数は、コンパイル時に定義した値へ置きかえられる
- チップ上のメモリ(RAM)を消費しない
構文例は以下となります。
※最後に「;」はつきませんので注意!
#defineを使ったサンプルスケッチ(コード)がこちら。
単純なLEDのON/OFFです。
//サンプル1 #defineの場合 #define ledpin 13 void setup() { pinMode(ledpin, OUTPUT); //13番ピンをOUTPUT指定 } void loop() { digitalWrite(ledpin, HIGH); //13番ピンをHIGH delay(1000); //1秒待つ digitalWrite(ledpin, LOW); //13番ピンをLOW delay(1000); //1秒待つ }
このスケッチでは、#defineによりコンパイル時にledpinという変数が全て13に置き換えられます。
constについて
次に、constについて確認していきます。
- 変数を読み取り専用にする
- 型を持つ変数として使えるが、値は変更できない
- constで定義した変数に値を代入しようとするとコンパイルエラーになる
- constを付けた変数はスコープのルールに従う
スコープのルールに関しては、下記をご確認ください。
とても大事なルールです。
constを使ったサンプルスケッチ(コード)がこちら。
単純なLEDのON/OFFです。
//サンプル1 #defineの場合 const int ledpin = 13; void setup() { pinMode(ledpin, OUTPUT); //13番ピンをOUTPUT指定 } void loop() { digitalWrite(ledpin, HIGH); //13番ピンをHIGH delay(1000); //1秒待つ digitalWrite(ledpin, LOW); //13番ピンをLOW delay(1000); //1秒待つ }
最初の変数の定義の仕方がことなるだけで、スケッチ(コード)の動作としてはまったく同じです。
これが、本だったりネットに転がってるスケッチ(コード)だったりでマチマチなわけです。
#defineとconstについて
公式リファレンスでは#defineよりもconstを使うことを推奨しています。
※しつこいですが、Arduino 入門 番外編 10 変数のスコープ(ローカル変数、グローバル変数)をご確認ください。
スコープのルールに従うというのは、間違いやミスを少なくできますよということにつながります。
#defineとても便利です。
しかし、その便利さが欠点でもあります。
それは、定義した変数が全て置き換えられるということ。
※利点でもありますが・・・。
#defineで定義した変数は、その変数がどこにいようともソースファイルをテキストのように扱い文字列の置換をしてしまうのです。
そう、これは意図しない置換をしてしまうことがあるということにつながります。
短いコードであれば、全体を把握できるので問題ありません。
しかし、コードが長くなれば長くなるほど把握するのに限界があります。
そのため、スケッチ(コード)はスコープのルールを意識して書くことが大事です。
これが、constを推奨している理由です。
考えてみてください。
スケッチ(コード)が長くなるため、繰り返し処理する部分を関数化したとします。
その関数の中に対して#defineで定義された変数と同じ変数を使っていたらどうなるでしょう。
やはり、置換が行われてしまいます。
ちょっと考えると置換が行われる範囲がおそろしいですよね・・・。
ちなみに、関数化に関しては以下にて解説しています。
興味のある方は覗いてみてください。
ということで、管理人は以下のように考えます。
中級、上級レベルになって、#defineの意味を理解したうえで使う。
管理人は、本日からconstを使うことを基本とします。
#defineって何?
じゃ、#defineってなんだろうって思いますよね。
一言でいうと、マクロです。
マクロはconst定数のようにデータの型をもちません。
コンパイル時にスケッチ(コード)の該当箇所を置換するマクロ機能です。
もっと詳しく解説したいとことですが・・・
管理人の知識では、この程度の解説が限界です。
#defineは何に使うんだ!
何に使うのでしょう・・・。
自問自答中です。
Arduinoのスケッチ(コード)に関しては#defineを使わないでも当面大丈夫と考えています。
まとめ
「Arduino 入門 番外編 15 【#define】と【const】」
いかがだったでしょうか?
Arduinoに色んなことをさせようと考えると、スケッチ(コード)がどんどん複雑になっていきます。
これからは#defineを使わずに、スケッチ(コード)を書くようにしたいと考えます。
Arduino 入門 番外編 09 スケッチ(コード、プログラム)の関数化
Arduino 入門 番外編 10 変数のスコープ(ローカル変数、グローバル変数)
とあわせて、わかりやすいスケッチを作成するように意識してみましょう。
スケッチ(コード)のデバック時に効果が実感できるはずです!
次回の番外編も、スケッチについて情報を発信したいと考えています。
最後に
疑問点、質問などありましたら気軽にコメントください。
この電子部品の解説をしてほしい!などなどなんでもOKです。
リンク切れ、間違いなどあればコメントいただけると助かります。
Arduino入門編、番外編、お役立ち情報などなどサイトマップで記事一覧をぜひご確認ください。
Arduino入門編、Arduino入門編2で使用しているUNOはAmazonにて購入可能です。
Arduino入門編では互換品を使用。
Arduinoはオープンソース。
複製して販売するのもライセンス的に問題なし。
そのため互換品の品質も悪くなく、それでいて値段は安いです。
正規品本体の値段程度で豊富な部品が多数ついています。
学習用、遊び用、お試し用には安価な互換品がおすすめです。
ELEGOO UNO キット レベルアップ チュートリアル付 uno mega2560 r3 nanoと互換 Arduino用
上記のものでも十分に多数の部品が入っていますが、最初からもっと多数の部品が入っているこちらもお勧めです。
Arduino入門編2では「Arduino UNO R4 Minima」「Arduino UNO R4 WIFI」にて遊ぶため今のところは正規品を使用。(まだ互換品が・・・ほぼない)
Amazonでお得に買う方法
Amazonでお得に購入するならAmazon Mastercard、Amazonギフト券がおすすめです。
時期により異なりますが、様々なキャンペーンを実施しています。
\Amazonギフト券/
Amazonギフトカード キャンペーン
\Amazon Mastercard お申込み/
Amazon Mastercard 申し込み
いずれの場合もプライム会員である方がお得!!
\Amazon Prime 30日間の無料会員を試す/
無料会員登録
コメント
個人的に、Arduinoやってて#defineの使い道で一番多いのは#ifdefと合わせる方法ですね
#define DEBUG
void setup(){
#ifdef DEBUG
Serial.begin(115200);
Serial.println(“Debug enabled”);
#endif
}
こうすると、’DEBUG’が定義されているので”Debug enabled”とシリアル出力されます
#define DEBUGの部分を削除すると#ifdef~#endifまでのシリアル出力に関する部分はコンパイルされないので、シリアル出力もされません
ProMiniみたいな処理能力や容量の小さい物、スケッチやライブラリが長い場合も、あると便利です。これだけは代用が利きませんし。
コメントありがとうございます。
#defineと#ifdefの組み合わせ、便利ですね。
下記、なるほどと思いました。
>ProMiniみたいな処理能力や容量の小さい物、スケッチやライブラリが長い場合も、あると便利です。
プログラムは、あまり専門ではないのでコメントいただけるととても助かります。
ありがとうございました。
Arduino&C初心者です。ありがとうございます助かります
定数をどっちで定義すればいいのか悩んでました。1つスッキリしました。
コンパイルした時のメッセージ重要だったのですね、今まで無視していたのが、1つ理解が進みました。
コメントありがとうございます。
ブログを更新する励みになります!