- ベストアンサー
変数のスコープはどうするのがベター?
- 変数のスコープはどうするのがベター?C言語で組み込みプログラミングしています。
- 頻繁に呼び出される関数があり、その中でのみ使用する大きめの構造体がありますが、この構造体をグローバル変数として生成するか、関数が呼び出される度に生成するかで、どちらが良いのでしょうか?
- 高級言語では関数内で生成するようにしてカプセル化を図るのが一般的ですが、組み込みプログラミングでは生成コストやカプセル化の要件によって異なります。ケースバイケースですが、一般的にはグローバルで生成する、関数内で生成する、または関数内でstatic変数として生成する方法があります。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
できれば、2) が良いと思います。 まず、変数のスコープは可能な限り局所化する方が良いと言うことはあります。 また、その関数を使い回したり、変更したりしたときに、ローカルに置いておく方が、間違いにくいでしょう。 次に、auto にするか、static にするかですが、一般的にいって、Cでstatic変数を使う本来の用途は、関数から抜けたときでも変数を保持するためです。 なので、そうでない変数をstaticにすると、他の人が(または将来)コードを読んだときに、誤解を招く可能性がわずかながらあります。 さらに、auto変数の生成は、(malloc() で確保するのでなければ)多くの実装で、スタックポインタをそのアドレス分ずらすだけです。 いずれにしても、関数の呼び出しとリターンの方が、実行コストは高いので、生成コストを気にする必要はありません。 さらにもうひとつ、もしも、組み込みシステム故に、メモリの制約がきついのであれば、auto変数の場合、その関数が呼ばれていないときには、構造体に割り当てられる予定のメモリは、使い回しができますが、static で確保してあれば、その領域は常時確保されてしまうことになります。 このため、他の関数で使用可能なメモリがわずかながら減少します。 と、ここまで書いてきましたが、組み込みシステムで、大きなauto変数を使うのは、「スタックサイズの決定」という点での困難があります。 ローカル変数であっても、static で確保されていれば、メモリマップで、データセグメント(のようなところ)に割り当てられますから、実行中に、この変数の割り当てが失敗するという危険性はありません。 しかしながら、auto変数として定義すれば、(多くの実装では)関数呼び出しの度にスタックから領域が確保されます。 従って、実行中のどの場所でも、スタックを使い切らない量を「スタックサイズ」として確保する必要があります。 このスタックサイズの決定をサボるためには、3) のstaticでの確保が、楽です。
その他の回答 (4)
- jjk65536
- ベストアンサー率59% (66/111)
最近は組み込みでもリッチな環境が増えてきています。 OSが載っててメモリが512MBあったりとか、CPUが1GHzくらいあったりとか。 そういった環境では 読みやすさ > メモリ効率、実行コスト となるようにコーディングしますし、マイコンのような非力で低メモリの 環境では メモリ効率、実行コスト > 読みやすさ に優先度が変わるんじゃないでしょうか。 さて、質問者様の組み込み環境はどの程度リッチでしょうか? 3)についてですが、他の人が読んだ時になぜstaticが付いているのか 分かりにくいと思います。 積極的に値を保持したい意図がない変数でstaticついてると、 時間が経って自分で読んだ時にも混乱しそうです。 ところで、職業柄Cで書かれたオープンソースをよく読むんですが、 OSSでは2)が多いですね。 僕自身が組み込みでコードを書く際は、まず一番読みやすい2)でコーディングし、 パフォーマンスに問題がある場合にボトルネックを探し、他の手法を検討します。 もっとも、パフォーマンス上問題になるのはたいてい別の場所です:-P
お礼
今回私が書いている対象はマイコンですので、メモリは512kBです。 OSSでは2)が多いということで大変参考になりました。 どうもありがとうございます。
- jacta
- ベストアンサー率26% (845/3158)
その構造体がどの程度の大きさなのか、あるいはどんな使われ方をするのかにもよるでしょうが、普通は3)でしょうね。
お礼
3)が良いということで、いろいろなご意見あり参考になります。 ありがとうございます。
- D-Matsu
- ベストアンサー率45% (1080/2394)
組み込みの場合、どちらかというと性能的制約やメモリ管理(動的な要素が入ると総メモリ量の管理が難しい)といった方面の理由から大きな変数の動的な生成は一般的ではないような気がします。 そうなると1か3という話になる訳ですが、この2者であれば生成されるバイナリコードの差は基本的に存在しないはずなので好みで決めても特に問題はないと思います。 もっとも、「開発者が一人ではない」とか「開発規模が(組み込みでも)大きい」とか言った場合には「その関数でしか使わない」ことがソースコードレベルで明示できる3の方がマシではあるかと思いますが。
お礼
1)と3)ではバイナリでは差異はほぼないということで勉強になります。 どうもありがとうございます。
- notnot
- ベストアンサー率47% (4900/10358)
生成と言っても宣言文で初期化していない限り、スタックポインタを動かすだけなので、コストは掛かりません。 グローバルやstaticでOKということは、初期化を書いてないと思いますので、2) でしょうか。
お礼
生成コストはかからず、2)が良いということですね。 どうもありがとうございます。
お礼
使用メモリの最大値見積もりという観点はありませんでした。勉強になります。 見積もりを除いた場合は2)が良い、また生成コストは関数の呼び出し、リターンに比べて小さいという点で学習させていただきました。 どうもありがとうございます。