今回は変数について理解を深めます。
今回の説明内容
今回の記事では、変数について理解を深めていきます。
前回までの記事で、変数はこういうもので、スケッチではこのように書きます、と説明してきました。でも自分で変数使ってプログラミングするとなると、なんとなくまだフワフワした感じがあるのではないでしょうか。
そこで、今回は変数の性質について理解を深めます。ちょっと難しいところもあるかもしれませんが、じっくり読み進めれば大丈夫です!
複数の変数の宣言
今のところ使用している変数は時間を計測するための「count」という名前のもの1つだけです。
スケッチが複雑になってくると、使用する変数も増えてきます。複数の変数を使用する場合、例えば「a」「b」「c」という名前の3つの変数を使用する場合、もちろん以下のように一つずつ宣言しても全く問題ありませんが、
uint8_t a;
uint8_t b;
uint8_t c;
以下のように「,」(カンマ)で区切って宣言することもできます。
uint8_t a, b, c;
今後のスケッチでは適宜どちらかの書き方にします。
初期化
while文を使用した時間計測のスケッチでは、最初に計測に使用する変数を以下のように宣言しました。
uint8_t count;
変数を宣言した場合、用意された変数は適当な数字になっていますので、以下のように値を代入しました。
count = 1;
このように宣言をしたあと、値を代入する、というケースは多いので、変数を宣言するときに値を代入しておくことができるようになっています。
uint8_t count = 1;
このように宣言すると、1が代入されているcountという名前の変数を用意してくれます。
このように最初に値を設定しておくことを「変数の初期化」と呼んでいます。
変数の書き方についてはこれまで説明した内容で十分です。書き方はこれでいいとしても、ちょっと疑問が残ってるんですよね。
ちょっとした疑問
キッチンタイマーのスケッチでは、変数を利用して時間を計測することができるようになりました。変数の扱いはある程度わかったものの、ちょっと疑問が残ります。
その疑問とは、変数の宣言の位置です。特に詳しい説明もなく、時間を計測するための変数として「count」という名前の変数を以下の位置で宣言しました。
変数の宣言というのは、Arduinoボード本体に「〇〇という型の□□という名前の変数を用意してください」と依頼するものでしたよね。変数を用意してもらうように依頼するだけですので、変数の宣言は上の位置以外ではダメなのでしょうか。例えば、以下のように変数を宣言するとどうなるのでしょうか。
今回の記事では、このちょっとした疑問から出発して、変数の性質について理解を深めていきます。
変数を宣言する場所のルール
変数を宣言する場所のルールは、大きく2つあります。以下、それぞれのルールについて説明します。
1. 変数を使う前に宣言する
ひとつは「変数を使う前に宣言する」というルールです。以下のように変数を宣言する前に変数を使うと、例のごとく「そんな変数は知らない!」と英語で怒られます。
宣言する前に使ったとは言っても、もうちょっと後の方で宣言してるのに、、、って気もしますよね。でもArduino IDEはスケッチを解釈するとき、最初の行から順番に1行1行みていきます。たとえ次の行に変数宣言があったとしても、変数を宣言する前に使用すると怒られます。
ところで、変数の宣言は変数を使用する前であれば大丈夫なのはいいとして、前と言ってもそれなりに範囲がありますよね。
変数を宣言する位置は、使用する前であればどこでもいい、というわけではありません。
2. 宣言した変数は『{』と『}』で囲まれた内部のみで有効
ここでもうひとつ、とても重要なルールの登場です。
その重要なルールとは「宣言した変数は『{』と『}』で囲まれた内部のみで有効」というものです。ちょっとわかりづらいですので実際のスケッチを見ながら確認していきます。
キッチンタイマーで時間を計測するときに使用した変数「count」は、以下の位置で宣言しました。
この変数は、loopの「 { 」と「 } 」で囲まれた内部で宣言しています。変数countは宣言したあと、「 { 」と「 } 」の内部のみ有効ですので、「count」が使えるのは以下の範囲内です。
ところでこのスケッチをよくみると、for文のところに「 { 」と「 } 」がありますよね。この内部ではどうなるのでしょうか。
このように「 { 」と「 } 」の内部に「 { 」と「 } 」がある場合、その内部の「 { 」と「 } 」で囲まれた部分でも使うことができます。
このように、変数を宣言すると、宣言した階層より下の階層の「 { 」と「 } 」で囲まれた部分でも使用することができます(階層が何重になっていても、変数宣言したところより内部であれば使用できます)。ということは、以下の場所で「count」を宣言した場合はどうなるのでしょうか。
「count」は、setupとloopの「 { 」と「 } 」の1階層上で宣言していますよね。
先ほどのルールでは、変数を宣言した階層より下の階層にある「 { 」と「 } 」の内部でも使用することができる、と説明しました。つまり、上のように「count」を宣言すると、宣言した行以降のところで(setupとloopのどちらの「 { 」と「 } 」の内部でも)使用することができるようになります。
このように、変数は宣言した位置で使用できる範囲が決まります。この使用できる範囲のことを意識高い系の言葉では「スコープ」と呼んでいます。「スコープ」は日本語では「範囲」という意味なので、「変数の有効範囲」とか言えばいいような気もしますが「変数のスコープ」と呼びます。
「スケッチのそこで変数を宣言したら、この場所はその変数が使える範囲じゃないよ」というのではなく「スケッチのそこで変数を宣言したら、ここはその変数のスコープ外だよ」というような言い方をします。
ローカル変数とグローバル変数
変数には使える範囲(スコープ)のルールがあることがわかりました。ここでさらに変数を使用できる範囲の観点から変数の種類を分類する言葉がありますので覚えることにしましょう。
最後の例のように、どこの「 { 」と「 } 」の内部にもないところで変数を宣言すると、その宣言した行以降から最後の行までの範囲で使うことができます。
このように宣言した変数はスケッチの広範囲で使用できるため「グローバル変数」と呼んでいます。「グローバル」は日本語で「全体的な」というような意味です。
一方で、タイマーの時間計測で使用した変数のように、特定の「 { 」と「 } 」の中で宣言した変数は、その内部のみで使用できます。
このように部分的に使用できる変数を「ローカル変数」と呼んでいます。「ローカル」は日本語で「局所的な」というような意味です。
ところで、変数にはスコープがあり、宣言する場所によってグローバル変数とローカル変数があることはわかったのですが、またちょっと疑問が出てきてしまいました。
例えば、タイマー時間を計測するために「count」という名前の変数を宣言する場合、グローバル変数で宣言しても、ローカル変数で宣言しても、どちらも問題なく動作します。
では、変数の宣言はどこで行うべきなのでしょうか???
グローバル変数で宣言すればどこでも使えるので、全部グローバル変数で宣言してしまった方が安心のような気がしませんか?
そこで、Arduinoボード本体がグローバル変数やローカル変数をどのように扱っているのか、Arduinoボード内部で何が起こっているのか、変数はどのように宣言するのが適切なのか、次回の記事で解明していきます。
先ほどのエラーの意味
今回の記事はここまでですが、もう少し深掘りしたいと思います。今後の記事の理解には影響しませんので、難しいようでしたら飛ばしていただいても構いません。
ここまでの説明で、変数の宣言や使い方のルールがわかりました。
この記事の最初の方で、変数宣言の前に変数を使用するスケッチを検証してみました。当然ながらエラーになりました。
今までの知識でエラーの意味が分かりますので、Arduino IDEが何を言っているのか解読してみましょう。
下の方に何やら英語でグダグダ文句を言われていますが、日本語では以下のような内容です。(多少意訳部分があります)
Kitchen_timer: 39行目の8文字目 : 「count」がこのスコープで宣言されていないんですけど!
for( count=0; count<TIMER_JIKAN; count++) {
^
ここ。これ以上付き合うの無理なんでもうやめた
「count」がこのスコープで宣言されていないんですけど!
ということで「スコープ内で正しく変数が宣言されていない」と怒ってますね。(2回言わなくてもいいのにって気もしますが…)
変数countはスコープ内で最後に宣言していますので「スコープ内で宣言されていない」という指摘は正しくはありませんよね。でも手は怒りっぽいようですので、細かいことを指摘するのは得策ではないです。わかりました、ということで、Arduino IDEに怒られたら素直に従ってスケッチを修正するようにしましょう。
for文での変数宣言
最後に、よくみるプログラミングパターンがありますので確認しておきます。
for文で一定回数繰り返す、という処理はよく出てきます。
繰り返し処理をfor文で書く場合、繰り返し回数を数える変数はfor文の中でしか使わないですよね。その場合、以下のような書き方もあります。
for( uint8_t count=0; count<5; count++) {
処理;
処理;
}
このようにfor文の初期式で変数宣言をすることができます。
このように宣言した変数はfor文のスコープ内、つまりfor文の「 { 」と「 } 」の中のみ有効、という点に注意してください。
更新履歴
日付 | 内容 |
---|---|
2019.9.11 | 新規投稿 |
2021.8.25 | 新サイトデザイン対応 |
2022.2.15 | for文の説明追加 |
この、「scope」というのは思考の範囲を指すタイプの「範囲、領域」って意味みたいですね。
「領域展開(某漫画に出てくるエリア限定施行者無敵固有空間)」が「Area expansion」となる事から察するに、プログラムコードを文字の羅列と捉える前に、あるひとつの脳みそ?的に捉えている感じがします。
そう思うと、エラーで「(上の記憶から順番に考えてるのに)考えられる範囲に定義がなくて困るんですけど!」となるのはまあ、確かにって思いました。
コメントどうもありがとうございました!
深い考察ですね…
う〜ん、って考えさせられました。
ご指摘いただいて確かに、と思ったのが、プログラムは著作権の対象なんですよね。そもそも著作権は「思想または感情を創作的に表現したもの」とありますので、プログラムの本質はコードではなく、その裏の思想ってことなんですかね。そのために思考の範囲を意味する「scope」という単語が使われいてるのでしょうか。
なんだか奥深いですね。色々と考えさせられました。どうもありがとうございました。