人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

C, Java の変数の定義位置についての質問です。

C では「オート変数はブロックの先頭で定義する」スタイルが多く、
たしか Java の coding convention でもそれが推奨されていたと思います。
このスタイルは、変数の定義と使用箇所が離れるため読みにくいと思うのですが、
なぜ推奨されているのでしょうか?

ちょっと考えると「そのブロックで使用されている変数が一覧できる」というメリットがあるような気がしますが、
このスタイルが守られない場合も多いため、実際には「一覧」にはならないとおもいます。
そのメリットを活かすためには「ブロックの最初以外で定義したら文法エラー」とすれば良いと思うのですが、
そうなってません。

* どういうメリットがあるのか?
* なぜ文法で強制しないのか?
について教えてください。

●質問者: imsut
●カテゴリ:コンピュータ
✍キーワード:Java エラー スタイル ブロック メリット
○ 状態 :終了
└ 回答数 : 9/9件

▽最新の回答へ

1 ● pyopyopyo
●20ポイント ベストアンサー

古いC言語では、オート変数はブロックの先頭でしか定義できませんでした。これは言語仕様で定められています。

そのため厳密なCコンパイラでは、現在でも「ブロックの最初以外で定義したら文法エラー」となります。

おそらくこのような歴史的経緯が背景にあるのだと思います。

そして「変数の定義と使用箇所が離れるため読みにくい」という理由から、

最近のC言語の仕様では、自動変数はどこでも宣言できるように仕様が拡張されています。

そしてコンパイラのオプションで、「ブロックの最初以外で定義したら文法エラー」とするか否かをプログラマが

選択できるようになっています。

ですので、

* どういうメリットがあるのか?

については、メリット、デメリットがあるが、それ以外に歴史的経緯もある。

* なぜ文法で強制しないのか?

C言語に限れば、コンパイラのオプションで選択できる

ということになります。

◎質問者からの返答

ありがとうございます。

「変数の定義と使用箇所が離れるため読みにくい」と感じていたのは私だけではないのですね。

なぜ Java がそのスタイルを推奨しているのか不思議です。

調べたところ C99 でブロック途中での定義が可能になったようですね。


2 ● syuzabu
●15ポイント

こんにちは。

> このスタイルは、変数の定義と使用箇所が離れるため読みにくいと思うのですが

> ちょっと考えると「そのブロックで使用されている変数が一覧できる」というメリットがあるような気がしますが、

読みにくいと感じるのは imsut さんの主観ですよね。

僕は後者の変数が一覧出来た方が見やすいと思います。(コレも主観)


> このスタイルが守られない場合も多いため、実際には「一覧」にはならないとおもいます。

う?ん、ちゃんとした現場ではコーディング規約があるので

変数の宣言位置についてはそれに沿って守られるハズです。

・・・規約があるのに守らない人がいるのは組織として問題があります。(^-^;)


> * どういうメリットがあるのか?

例えば関数の中にA、Bと二つの分岐処理があったとします。

AとBでは全く異なる変数を使用するとします。


関数の初めで変数宣言を行うとその分のメモリを使用しますがAの分岐処理ではB用の変数、

Bの分岐処理ではA用の変数宣言分が不要で、無駄なメモリ消費となります。


分岐処理内で変数宣言を行うとA、Bは必要な分だけメモリを使用出来る形となります。


メモリ制限がある環境などでは後者の方が有利です。

メモリ制限がない環境では前者の方が一般的に見やすいとされてます。


・・・のように、ある程度自由度を持たせてあげないと

様々な分野のソフト開発には向かない言語となってしまうからではないでしょうか。


長文になりましたが、なんとなくこんな感じで。

◎質問者からの返答

> 関数の初めで変数宣言を行うとその分のメモリを使用しますがAの分岐処理ではB用の変数、

> Bの分岐処理ではA用の変数宣言分が不要で、無駄なメモリ消費となります。

> 分岐処理内で変数宣言を行うとA、Bは必要な分だけメモリを使用出来る形となります。

本当ですか?

その場合、その変数はヒープに確保されるのでしょうか?

スタックに確保されるなら、そのような挙動にはならないと思いますが・・・。

そういう動作をするコード例・環境が知りたいです。


3 ● pahoo
●25ポイント

変数宣言の位置について明確なガイドラインがあるのかどうか分からなかったので、以下は個人的な意見になります。

どういうメリットがあるのか?

コンパイラとしては、ブロックの冒頭で宣言してくれると助かります。

20年以上前の話ですが、ミニコン用のCコンパイラを移植している際に苦労したのがregister変数の扱いです。文字通りCPUレジスタに変数を割り当てるので、当時の、ただでも貧弱なCPUのレジスタをフル回転させるため、register変数の定義の有無で、それ以降のコードのアルゴリズムを変更していました。

register変数は関数の途中でも宣言できるわけですが、シーケンシャルにコンパイルしていたものですから、途中にregister変数があらわれると、関数の冒頭までさかのぼるってコンパイルし直すことをしていました。

また、一般的なauto変数についてはスタック領域に確保していました。スタックは1本しかないため、関数の冒頭で一気に定義し、関数終了時に一気に解放した方が、安定性の高いコードを生成することができました。関数処理の途中で、ジャンプやループ制御のためにスタック領域を共有するためです。

今はこんな厄介なことは起きないのですが、コーディングの慣習は、こうした過去の経緯を引きずっているのではないでしょうか。

なぜ文法で強制しないのか?

プログラムの不具合を防ぐ無意味では、auto変数には必要十分なスコープを持たせる必要があります。たとえばループ制御変数なら、ループ文の直前に宣言すれば良いと思います。ブロック冒頭で定義することは、必ずしも必要ではないからです。

ところが、変数の宣言手段を用意している言語は多いのですが、明示的に廃棄する手段は定義されていません(言語によっては変数を廃棄するメソッドが用意されていますが)。当該ブロックが終了した時点で自動的に破棄されるというのが暗黙のルールになっていますね。

ブロック末尾で廃棄されるということは、プログラムの対称性を鑑みて、宣言する位置もブロック冒頭の方が良いという考えがあります。

いずれにしても、廃棄する方式が定義されない限り、宣言する位置も強制することはできないということではないでしょうか。

◎質問者からの返答

> 20年以上前の話

こういう話を聞くのは楽しいですね。

プロセッサ性能による制約というのはたしかにありそうです。今はないでしょうけど。

> 一般的なauto変数についてはスタック領域に確保していました。

今はそれが普通ですよね。

それにしても、関数内で使用するすべての変数のサイズの合計を求めて、

その分 SP をずらせば良いので、定義位置とは関係ない気がしますが・・・。

「ブロックの先頭だけ見れば「すべての変数」が分かるから簡単」ということですかね。

> 明示的に廃棄する手段は定義されていません

brace ({, }) で囲えば、意味的には廃棄されますね。領域は多分解放されませんが。

> ブロック末尾で廃棄されるということは、プログラムの対称性を鑑みて、宣言する位置もブロック冒頭の方が良いという考えがあります。

その観点はありませんでした。たしかに「美しさ」という意味ではそうかもしれません。

「美しさ」に対するデメリットが大きすぎるとは思いますが。


コンパイラの移植とはおもしろそうなお仕事ですね。

大変参考になりました。


4 ● tarutatta
●15ポイント

Cでのお話になりますが、昔は関数の先頭でオート変数を定義しなければエラーになっていたはずです。

たしか、1999年に策定され、C++ の機能の一部を取り込んだ ISO/IEC 9899:1999 - Programming Language C(C99)からどこで宣言してもよくなったはずです。

(これは私の推測ですが、)昔の非力なコンピュータでコンパイルするとき、コード解析に時間がかからないようにするためにそうなっているのではないかと思います。

おそらく、メリットはそれだけです。コンピュータの処理速度が向上した現在ではデメリットしか生まないような気がします。

関数の頭でカウンタ変数を宣言すると、いらないバグを生むことになりますし、使用部位と宣言部位が離れるとコーディングの効率が悪くなります。

◎質問者からの返答

> 関数の頭でカウンタ変数を宣言すると、いらないバグを生む

まったく同感です。この質問もこのバグに当たったことがきっかけです。

今のコンパイラ・プロセッサなら、

変数の宣言位置によってコンパイル時間が(体感できるほど)変わるとは思えないですし。

自分で書いといて何ですが「変数がブロックの先頭で定義されていると、

一覧できるから便利」というのは、具体的に何が便利なんですかね?


5 ● しおり
●15ポイント

◆どういうメリットがあるのか?


□Java の場合

Java プログラミング言語に関するコード規約 - Declarations - Placement」には以下のように書かれていますが、よくわかりませんね。

Put declarations only at the beginning of blocks. (A block is any code surrounded by curly braces "{" and "}".) Don't wait to declare variables until their first use; it can confuse the unwary programmer and hamper code portability within the scope.

コード例を含めて超意訳すると、メリットはこんな感じでしょうか。


□C の場合


◆なぜ文法で強制しないのか?


また Java の場合、上記のコード規約でループ用の変数の宣言は例外としています。

◎質問者からの返答

ありがとうございます。

でも、あまり説得力を感じられませんね・・・。

> 定数の初期化は、代入と同時にしかできないから。

ブロックの途中の計算結果を定数に入れたいという状況もよく分からないです。


1-5件表示/9件
4.前の5件|次5件6.
関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ