<C言語入門/車載ソフト> 変数
こんにちは、レオハルです。
車載ソフトで利用するC言語入門シリーズ「変数」です。
※通常のC言語解説とは、異なり組込み・車載ソフトに特化した記載があります。ご注意ください。
変数とは
「変数とは、箱です」
という説明を入門書などでは、よく見聞きします。
しかし、この説明では、十分な理解は得られません。
特に車載ソフトなどの組込み系の場合、”メモリ”を意識した理解が必要になります。
「変数とは、データを格納するためのメモリ上に確保された領域です」
データ毎に格納する領域を区別できるように名前を付けます。名前を付けたメモリ上の領域に対して、値を書いたり、読んだりすることができます。
イメージ図を簡単に作ってみました。
この例では、3つの変数を定義しています。
アドレス1000に、1バイトの変数①
アドレス1004に、2バイトの変数②
アドレス1008に、4バイトの変数③
このように、変数は、メモリ上のアドレスに指定したバイト長のデータを格納できるように領域を指定したものになります。
型
先ほどの例のなかで、1バイト、2バイト、4バイトのデータを定義していました。
これを指定するものが型になります。
変数として、定義した”メモリ上に確保された領域”には、どんな値でも格納できるわけではありません。あらかじめ、その領域にどんなデータを格納するのか指定する必要があります。
データの長さや種類を決めるものを型と呼びます。
ここで組込み系特有の注意が必要な話です。
型の種類は、マイコンによって異なることがあります。マイコン毎に用意されているマニュアルをよく確認しましょう。
ここでは、とある車載向け32ビットマイコンでの型を例に説明します。
ひと昔前のマイコンだと、8バイトの整数型がなかったり、浮動小数点型は扱えなかったりといったことがありました。
過去のマイコンでのソフト資産を流用することもあって、私の場合は、まだ8バイトの変数も浮動小数点型の変数も扱ったことはありません。でも、今後はマイコン性能も向上していますし、モデルベース開発の影響などもあり、利用機会は増えていくと思われます。ITSなどの画像処理系やAI活用している場合などは、既に使ってるんですかね、どうなんでしょう?
ちょっと脱線します。
組込み系では、多くの入門書等で最初にやるprintf()を使った''Hello World"は、やりません。そもそも基本的には、「文字」を扱いません。なので、printfを使ったデバッグもできません。
一般的な組込み入門では、LEDを点滅させるようなプログラムが''Hello World"の代わりになっています。今どきの言い方だと「Lチカ」です。LEDチカチカの略です。実際のデバッグでもこれに近いことをやって動作確認することが意外とよくあります。
定義・宣言
次に変数を定義・宣言する方法についてです。
変数を使えるようにするには、まず定義・宣言する必要があります。
変数の型 変数名 ;
例えば、下記のように「a」と「b」の変数を定義・宣言します。
char a ;
int b ;
これは、char型の「a」、int型の「b」という変数のメモリ領域を確保するという定義と、今から使うよという宣言を同時にしています。
定義と宣言を使い分けているには、理由があり、次のような違いがあります。
「定義」=実際にメモリ領域を確保するよ!
「宣言」=どこかに定義されているこの変数を今から使うよ!
変数についても、「宣言」だけを行うパターンがあります。
車載ソフトのようなある程度規模のあるソフトウェアの場合、ソースコードは複数のファイルに分かれて管理されます。別のファイルで定義されている変数を利用する場合には、「どこか別の場所で「定義」されている変数を使いますよ」という意味のextern宣言を行います。
extern long c ;
記憶クラス(グローバル・オート・スタティック)
C言語では、変数の有効範囲を示す記憶クラスというものがあります。
ソースコード上のどこにどう書くかによって変わります。
次の3つについて、覚えておくべきポイントを挙げます。
- グローバル変数
ソフトウェア全体で利用できる変数。
関数の外で定義するとグローバル変数になります。
別ファイルで利用したい場合は、extern宣言する。
静的領域と呼ばれる割り当てが変化しないメモリ領域に割り当てられます。 - オート変数
関数内でのみ利用できる変数。ローカル変数とも呼ばれる。
関数の中で定義するとオート変数になります。
auto とつけることがあるが一般的に省略します。
スタック領域と呼ばれる、一時的に確保されるメモリ領域に割り当てられます。
一時的に確保されているため、関数内の処理が終了すると、値は不定となります。スタック領域のメモリは、他の関数とも使い回しています。そのため、初期化しないと前の値が残った状態となるため、注意が必要です。初期化してから使いましょう。 - スタティック変数
ファイル内でのみ利用できる変数。
関数の外で"static"修飾子を付与して定義するとスタティック変数になります。
変数の命名
最後に変数の名前の付け方についてお伝えします。
C言語としては、名前の付け方は、かなり自由にできます。
しかし、製品としてソフト開発を行う場合には、保守性・可読性が求められます。
そのため、好き勝手につけてはいけません。自分の担当するプロジェクトで決められたスタイル規約・コーディング規約に従い命名するようにしましょう。
例えば、次のようなことを考慮し、命名するとよいでしょう。
例と合わせて記載します。
- 対象となる識別子(グローバル、オート、スタティック)
g:グローバル
a:オート
s:スタティック - 型(char, unsigned char, int…)
s1:char(符号あり1バイト)
u1:unsigned char(符号なし1バイト)
s2:short(符号あり2バイト)
u2:unsigned short(符号なし2バイト)
s4:int(符号あり4バイト)
u4:unsigned int(符号なし4バイト)
f4:float(単精度)
f8:double(倍精度) - 単語の繋げ方(キャメルケース、スネークケース、チェインケース)
車輪速度
WheelSpeed、wheelSpeed:スネークケース(アッパーキャメル、ローワー)
wheel_speed:スネークケース
wheel-speed: - 略語の付け方
abs:absolute(絶対値)
add:append(加算)
btn:button(ボタン)
ctrl:control(制御・コントロール)
cnt:count(カウント)
などなど - 文字数制限
昔のコンパイラでは、31文字までしか認識できないものがありました。
今どきのコンパイラであれば問題になることは、滅多にないと思いますが、自分でつける場合は、長くなりすぎないように気を付けましょう。
ツールを使ってオードコードで出力するような場合長くなることもあり、どうしようもないケースもあります。
実例
#include <studio.h> void add_chng(int s4_input); int s4g_add_Sum; /* グローバル変数 */ static int s4s_base_Value;/* スタティック変数 */ void main(void) { int s4a_tmp_input1; /* オート変数 */ s4a_tmp_input1 = s4s_base_Value * 2; s4g_add_Sum = s4g_add_Sum + s4a_tmp_input1 ;
add_chng(s4a_tmp_input1); } void add_chng(int s4_input) { s4s_base_Value = s4_input+ 1 ; }
特に意味のあるプログラムではありません。
グローバル変数・オート変数・スタティック変数の定義場所に着目してみてください。
グローバル変数とスタティック変数が0からスタートして、main()関数が10回連続で実行されると、3つの変数はどんな値になっているでしょうか?
C言語学習におススメの書籍
【C言語/プログラミング初心者の方】
【入門卒業レベルの方】
【組込み向け】