• 締切済み

グローバル変数のよくない使い方とその改良例

C言語の勉強をしています。 グローバル変数を多用するのはあまりよくないと聞きました。 どこでいつ書き換えられるのか把握しづらい等々、言われることは理解できるのですが、 では具体的にどうするのがよいのか分からないのです.. 例えば、異なったファイル内の複数の関数から参照したり、書き換えたいような変数が あった場合、ついついグローバル変数を使いたくなってしまうのですが、このような ケースではどのようにするのがよいのでしょうか。 簡単なC言語の具体的な例で教えてください。 よろしくお願いします。

みんなの回答

  • ency
  • ベストアンサー率39% (93/238)
回答No.9

ちょっと別の視点から。。。 グローバル変数を使うことが良くないといわれているのは、「その変数が一つしかないこと」が理由だと私は思っています。 つまり、変数が一つしかないことの弊害を考えれば、「なぜグローバル変数がよくないのか」がわかってくるのではないでしょうか。 たとえば、ある機能の状態をグローバル変数を使って管理していた場合、その機能は同時に一つしか動かすことができません。 その後、その機能を複数同時に動かす必要が出てきたとしても、機能の状態は一つのグローバル変数で管理している以上、対応できません。 また、上記のような対応が必要になった場合に、「それじゃあ配列にして管理しよう」となったときに、それまで参照していた箇所すべての変数を配列に置換しなければいけなくなる…といった問題もありますよね。 そしてもちろん、グローバル変数にしてしまうと、その変数をいつだれがどこで更新するかわからないので、不具合発生の要因になりやすく、またその場合の解析も面倒になる…といった問題もあります。 ただし、グローバル変数も使い方によっては非常に便利なものなのは確かだと思います。 もし、どうしてもグローバル変数を使わなければいけない状態になった場合、私は以下のようにしています。 (1) ヘッダファイルを2つ用意する。 (2) そのヘッダファイルの一方にグローバル変数をextern宣言し、もう一方には宣言しない。 (3) グローバル変数を使用しない人にはexten宣言なしのヘッダファイルをインクルードしてもらい、使用する人にはextern宣言ありのヘッダファイルをインクルードさせる。 こうすることで、ファイルをまたいだ状態でファイル内の静的変数相当のことができるようになります。 # っていうか、それなりの規模のプロジェクトで仕事をしていれば、ヘッダファイルを内部公開用と # 外部公開用の2つに分けていると思うので、そんな場合には「内部公開用」のほうに入れておけば # 外部からの不要な参照を回避できます。 # そもそも、それなりの規模のプロジェクトであれば、これくらいの情報隠蔽は当たり前のように # 行われていると思います。 オブジェクト指向言語が使えれば、必要に応じてインスタンス(オブジェクト)を複数生成することもできるし、情報の隠蔽もクラスのフィールド、メソッド単位でできるから、こんな苦労しなくても良いんだけどなぁ。。。 # いや、いろいろな制約から、C しか使えないプロジェクトにいるものでして。。。 このように、実装の仕方でグローバル変数の公開範囲を限定することも可能ですので、「悪いものは何が何でも使うな!」という話ではなく、メリットとデメリットをよく考えて柔軟に対応することも大事だと思います。

  • higeG
  • ベストアンサー率22% (4/18)
回答No.8

一概にグローバル変数が悪とは言えないのですが、一般的に以下の2点が懸念される点だと思います。(他にもあるかも知れませんが) 1.大きなプログラムでは、解析するのが困難になる 2.マルチタスクプログラミングでは、排他制御が必要になる 上記2点の内容に関しては、既に他の方から幾つか例が挙げられていますので端折りますが、では実際のプログラムで必要になった場合にどうするのかについても人それぞれだと思いますが、私は以下のようにしています。 1.C++ならクラス化して必ずアクセス関数経由で読み書きする 2.Cでも関連する関数群を1つのファイルにまとめてstaticをつける  →そのファイル内からの関数からしかアクセスできなくなります。  →他のファイルから参照したい場合は、やはりアクセス関数を作ります。 3.マルチタスクプログラミングでは、タスク間I/Fとしてやりとりする  →メールボックスやイベントフラグを使います。 4.それでもどうしても残るグローバル変数はメモリ仕様書を作成する  →変数の意味、取り得る値の内容、セット/リセットタイミング等を明記する。 何れにせよ、どういう内容の変数で、いつどこで変更されるのかを誰が見てもすぐに分かるようにすることが肝心かと思います。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.7

グローバル変数のよくない使い方に関してですが、逆に、どんな場合にグローバル変数でなければならないか、あるいはグローバル変数が望ましいかを考えてみるとよいでしょう。 たとえば、メモリマップトI/Oや(プロセッサ間の)共有メモリなど、ハードウェアを直接制御する場合には、それらをグローバル変数として扱わざるを得ないことがあります。 あるいは、本来であればstaticを付けて内部結合にすべき静的変数でも、ライブラリなどでは、プログラムサイズを最小にするため、1関数1ファイルになるように分割することがよくあります。この場合にはグローバル変数にせざるを得ません。 いずれも効率を改善するために必要なのであって、効率を無視するのであれば、グローバル変数にしなくても、別の方法はいくらでもあります。 また、グローバル変数といってもconst付きであれば、値が変化することがないのでグローバルでも害はほとんどありません。 次に、グローバル変数を使わないのであれば、具体的にどうするかですが、これはケースバイケースです。単にグローバル変数をなくせばよいというものではなく、無理なことをすれば、グローバル変数以上に悪いコードになってしまうこともあります。グローバル変数を使ってしまった具体的なコードを補足していただければ、それに対して具体的な変更案を示すことはできると思います。

回答No.6

Cでしょうか、C++でしょうか、VC++でしょうか。 なぜグローバル変数が好ましくないか、という問題は、理屈をいうより、 ちょっと行数の多いコードを書くだけで、痛感できます。 何かの値をグローバル変数に入れておくと、使うたびに、 「ここに入っている値は正しいだろうか」 「不用意に書き換えられていないだろうか」 という疑惑に悩まされ続けます。 もちろん、複数の人でコーディングする場合は、もっと深刻な問題があります。 では、どうしたらいいか、ということですが、一番簡単なのは、値をクラスや構造体にすることです。 頭の中だけで考えると、あまりピンとこないかもしれませんが、経験的にいって、これだと、あまり悩まないですみます。 くぐってみたら、こんなのがありました。 MFCですが、なんとなくイメージは分かると思います。 http://homepage3.nifty.com/mitui707/VisualC/VCdataclass.html/

  • matyrcry
  • ベストアンサー率47% (101/213)
回答No.5

あちこちから操作されるといえば、例に少し挙がってますが、たとえば 時間データなどですね。(標準関数のお世話にならずに自分でデータを 作って使っていると考えてください) 定期更新や端末操作などから、年、月、日、時、分、秒のデータを書き 換えることがありますが、書き換えている最中に読み出すと整合性が取 れずに泣き別れが発生します。 たとえば10分59秒から11分0秒に書き換えようとして、分だけ 変更したところで読むと11分59秒と読んでしまうなど。 グローバルだとこれを防ぐためにセマフォ機能で同時アクセスを禁止する とか行いますが、一回一回そういうコーディングしていくのは結構面倒で すし、書き忘れや書き損じも怖いですね。 こういうデータは、参照・変更を関数化して安全を保証してくれる管理ク ラスを設計して関数経由の間接操作で扱うほうがいいです。 セマフォ処理を関数化してもいいですし、書き換え中に参照側のプロセス を止めないようにしたい場合などもアクセス関数の工夫次第です。 この例だと、更新前に前データのコピーを確保しておいてから更新中フラ グを立て、読み出し側は更新中ならコピーを読むように取り決めするとか できそうですね。

  • NNori
  • ベストアンサー率22% (377/1669)
回答No.4

>できましたら、これを具体的な例でご説明いただけませんでしょうか。 じゃあ、例えばコマンドラインで英語モードと日本語モードを切り替えることができるプログラムを考えてみましょう。つまり、モードをグローバル変数にいれたくなったわけです。 でも本当にそのモードはプログラムのすべての箇所で必要ですか?そうではないですよね?出力するときにさえ英語モードなのか日本語モードなのかがわかればよいので、グローバル変数にする必要はないのです。 こういうときは、出力用のクラスを作って、それの初期化時にオプションを読ませて英語モードか日本語モードかをクラスの変数に覚えさせとけばよいのです。

回答No.3

入力と出力はすべてパラメータとして渡す。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.2

C言語の場合は、同じグローバル変数を使いたい関数群は、同じような機能を 持っていると考えられます。例えば日付計算に関する関数群、ファイルアクセスに関する関数群、など。そのような仲間の関数を1つのファイルにコーディングをし、そのファイル内だけの関数でグローバル化するのが一般的です。関数の仲間ごとにファイルを分けてコーディングをする、ということですね。 C++言語になると、その仲間の関数群を1つのオブジェクトのメソッド(関数)として定義し、オブジェクト内の変数は、オブジェクト内のメソッドで使う、といった設計になります。オブジェクト指向は、このような関数の設計でトラブルが発生しにくい構造に出来る、という面も重要です。 どちらも、基本は、機能の分割、分類、インターフェイス設計(関数の引数など)等が重要で、設計者の知識とセンスが問われます。

  • NNori
  • ベストアンサー率22% (377/1669)
回答No.1

>異なったファイル内の複数の関数から参照したり、書き換えたいような変数 こういう変数って一体なんでしょう? グローバル変数が悪いと言われるのは、こういう変数の本質を見極めることなしに安直に実装してはいけない、という意味です。 グローバル変数を使うと格好悪いというだけの理由であれば、グローバル変数集みたいな構造体orクラスを一個定義しておいて main に入ったときに1個alloc or new してやれば簡単に実装できます。 でもそれって本質的にグローバル変数を使ってるのと同じなんです。 そういうことではなく、異なったファイル内の複数の関数から参照したり、書き換えたいような変数は、「ない」はずなんです。

044128
質問者

お礼

> そういうことではなく、異なったファイル内の複数の関数から参照したり、書き換えたいような変数は、「ない」はずなんです。 ということは、そのような変数が必要になってしまうような関数やファイルの の作り方がよくないということですね。 できましたら、これを具体的な例でご説明いただけませんでしょうか。 (ちょっとまだピンとこないのです..)

関連するQ&A