• ベストアンサー

複数ファイルで使うグローバル変数の位置

メイン関数の処理で、関数A→関数B→関数Cという順序で関数が呼び出される場合(1関数1ファイルとします)、関数A,B,Cすべてで使用するグローバル変数の宣言を関数Bのファイルでおこなって、他のファイルではそれをexternするというのでも問題ないでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

問題ありません。 が、しかし、そのような方法は、実務レベルの場合は、行いません。 以下のような方法をとります。 ファイル名:xxx_ext.c 変数のみを宣言したファイル。 ファイル名:xxx_ext.h 上記の変数のみを宣言したしものをexternで参照するファイル。 ファイル名:func_a.c 関数Aのファイル。 このファイルで、#include xxx_ext.h する ファイル名:func_b.c 関数Bのファイル。 このファイルで、#include xxx_ext.h する ファイル名:func_c.c 関数Cのファイル。 このファイルで、#include xxx_ext.h する 上記のようにすることで、externで参照する変数が1つのファイル内に閉じこめられるのでメンテナンス性がよくなります。たとえば、ある理由があって、変数Xの型をintからdoubleに変えることを想定してください。 xxx_ext.c とxxx_ext.hの2つのファイルのみが変更対象 となります。 上記のようにしない場合は、3つのファイル(あるいはそれ以上)を変えることになります。

BIGMON
質問者

お礼

詳しい説明ありがとうございます。今回の場合はxxx_ext.h はあるのですが、xxx_ext.cがなくて、どこにグローバル変数をおいたらいいか困っていたところです。xxx_ext.cを作ればいいのですが、融通がきかないものでして。。。

その他の回答 (4)

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

No3 ency です。 No4 rentahero さん: > #3のようにするなら、C++にしてクラスにした方がいいのでは。 確かにそうなんですけどね。 プロジェクトで使用する言語って、個人がどうとか言ってどうになるものでもないですし。。。 # ちなみに、私は組込み系やってます。 # アプリ系は C++ を使ったりしているようですが、下回りはまだまだ # C から離れられないですね。 # ドライバ屋さんなんかは、アセンブラ使ったりしているところも # ありますからね。 No4 rentahero さんの参考 URL の方法は、よく見かける方法ですね。 ただ、extern をはずすマクロをどこで define するかという話がありますし、これって結局「どこに定義するべきか?」というのと同じ話になりそうな気がします。 でも、ヘッダファイルとの不整合が発生しにくいという点では、良い方法ですね。 あと、No3 の例で、ヘッダファイルに extern が抜けてますね。。。 # 失礼しました。

BIGMON
質問者

お礼

皆様解答ありがとうございます。最初はグローバル変数は使わないでstatic宣言してget関数set関数をつくって対応するはずだったんですが、関数の数も変えてはいけないことになってしまったもので。。。大変参考になりました。

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.4

#3のようにするなら、C++にしてクラスにした方がいいのでは。 まあともかく。 私もグローバル変数を使いたくないのはやまやまなので、私ならそのグローバル変数を使う関数をひとつのファイルにまとめるようにしますね。それならファイルスコープ変数ですみますから。 グローバル変数を使うときのうまいやり方が Cプログラミング診断室(参考URL参照)に紹介されています。 あと別解として、グローバル変数の代わりに構造体をつくり、mainにてstaticで静的に確保し、各関数にポインタを渡してやればよいのでは?

参考URL:
http://www.pro.or.jp/~fuji/mybooks/cdiag/cdiag.5.4.html
  • ency
  • ベストアンサー率39% (93/238)
回答No.3

ファイル分割する際には、機能ごとにファイルを分割すると思います。 で、いくら全体から参照される変数とはいえ、その変数はどこかの機能に属しているはずです。 通常は、その属しているファイルに定義すれば良いと思います。 それで、ファイルスコープの変数定義をしておいて、アクセス用の関数を用意します。 ------------------------------------------------ hoge.h ------------------------------------------------ int hoge_get_nantoka( void ); ------------------------------------------------ ------------------------------------------------ hoge.c ------------------------------------------------ #include "hoge.h" static int hoge_nantoka; static void hoge_hoge_kantoka( void ); int hoge_get_nantoka( void ) { return hoge_nantoka; } static void hoge_hoge_kantoka( void ) { hoge_nantoka = 100; } ------------------------------------------------ ------------------------------------------------ piyo.c ------------------------------------------------ #include "hoge.h" int piyo_print_nantoka( void ) { printf( "nantoka=%d\n", hoge_get_nantoka()); } ------------------------------------------------ 理由は、他のモジュールから無条件で書き換え可能な変数は作りたくないからです。 # というか、他の人に悪さされたくなかったら、このような設計に # なってしまうと思います。 複数ファイルから、書き換えが発生するグローバル変数は極力避けたほうが良いと思います。 # 現実的に無理な場合もあるでしょうけど、そのような場合には # ファイル分割の仕方を見直すべきだと思います。 いわゆる「カプセル化」ってやつですね。 オブジェクト指向でなくても、このようなことは複数人で運営しているプロジェクトなら、当たり前のようにやっていると思います。 # 知らない人に、知らないところで、実は変数書き換えられていました、 # なんてことを起こさないためにもね。 さて、そうはいってもモジュールが機能追加等でだんだん大きくなってきて、同じモジュールでもファイル分割をする必要が出てくることもあるでしょう。 その場合、ヘッダファイルもモジュール内部用のヘッダファイルと、モジュール外用のいわゆる公開ヘッダファイルに分割すると良いでしょう。 ------------------------------------------------ hoge.h ------------------------------------------------ /* 公開ヘッダファイル */ int hoge_get_nantoka( void ); ------------------------------------------------ ------------------------------------------------ hoge_prv.h ------------------------------------------------ /* hoge のプライベートヘッダファイル */ /* 公開ヘッダファイルはインクルードしておく*/ #include "hoge.h" int hoge_nantoka; void hoge_hoge_kantoka( void ); ------------------------------------------------ ------------------------------------------------ hoge_a.c ------------------------------------------------ /* プライベートヘッダファイルをインクルードする */ #include "hoge_prv.h" int hoge_get_nantoka( void ) { return hoge_nantoka; } ------------------------------------------------ ------------------------------------------------ hoge_b.c ------------------------------------------------ /* プライベートヘッダファイルをインクルードする */ #include "hoge_prv.h" void hoge_hoge_kantoka( void ) { hoge_nantoka = 100; } ------------------------------------------------ ------------------------------------------------ piyo.c ------------------------------------------------ /* hoge の公開ヘッダファイルをインクルードする */ #include "hoge.h" int piyo_print_nantoka( void ) { printf( "nantoka=%d\n", hoge_get_nantoka()); } ------------------------------------------------ このようにしておけば、万が一他のモジュールからのアクセスがあった場合、運がよければエラーをはいてくれますし、最悪でも警告は出してくれるはずです。 # ヘッダファイルの中でヘッダファイルをインクルードすることに対する # 賛否はあるようですけど、私はこうしています。 ま、話が本来の趣旨とは関係ない方向に行ってしまいましたが。。。 これがふつうだと思っていたんだけど、どうなんでしょうかねぇ。。。 # 誰に教わったとか言うんじゃないけど、実運用上こうしないと # 余計なバグの温床になりかねないと思いますし。

  • -izayoi-
  • ベストアンサー率45% (48/105)
回答No.1

問題ないですよ。

BIGMON
質問者

お礼

解答ありがとうございます。安心しました。関数Aだけで異常終了してしまった場合関数Bは通らないのに大丈夫かなあ?という気がしてしまうものですから。。。

関連するQ&A

  • 外部変数について

    今Vine Linuxを使ってC++でプログラムを書いているのですが教えて頂きたいことがあります. C++の初心者の為,変なことをお聞きしますがお許しください. extern宣言で他のソースのローカル変数を参照する方法はないのでしょうか? 例えば,a.cとb.cというソースがあったとします. a.cの関数内でint i;と宣言されている変数をb.cからextern int i;という風にしたいのですが, こうするにはa.cでグローバル変数としてint i;を定義する以外方法はないのでしょうか? できればグローバル変数を使いたくないのですがこれ以外では無理でしょうか? あともう一つお聞かせ下さい. メイン関数の引数を別の関数,またはソースで使うということはできないのでしょうか? int main( int argc, char *argv[] )のargv[1]というのを別の関数で使用したいのですがこれも無理でしょうか? 馬鹿な質問だとは思いますが,どなたかお答え頂けますでしょうか? よろしくお願いします.

  • グローバル変数

    分割コンパイルで、持ちいる変数をヘッダーファイルに宣言しました。 ヘッダーファイル内で次のように宣言し、メインの関数でない場合にはexternになるようにしました。 メインなら FILEは1 それ以外なら0 #if FILE   unsinged int inputNo; #else  extern unsigned int inputNo; #endif しかし、リンクをさせると error LNK2001: 外部シンボル "_inputNo" は未解決です と出てしまいます。解決策はあるでしょうか? プロジェクトの設定の関係でしょうか?よろしくお願い致します。

  • ソースファイルの分割について

    a.h クラスの定義 a.cpp クラスのメンバ関数の定義 b.h #include "a.h" クラスの定義 b.cpp クラスのメンバ関数の定義 ----c.cpp---- #include "a.h" #include "b.h" a.hで定義したクラスの宣言 b.hで定義したクラスの宣言 メインの処理 ----------------------------------------- b.cppで定義しているクラスのメンバ関数にて a.cppで定義したクラスのメンバ変数にアクセスしたいのです。 どうするのが一番良いのでしょうか? a.cppにメンバ変数を返すだけの関数を定義してb.cppでc.cppで宣言したa.hのクラスを extern宣言してみたのですがエラーが出てコンパイルが通らないです。

  • VB6で、変数の値を別ファイルの変数に引き継ぎたい

    AというVBのソースファイル(.frm)内に関数の呼び元があり、 その関数がBというファイルにあります。 その関数内で値が設定される変数を、Bファイルのグローバル変数とし、 また、Aファイルのグローバル変数として同じ名前の変数を宣言したとしても、 やはりB内で関数の実行が終了し、Aに戻った際には、変数は別のものとみなされている ようで、B内関数で設定された値がAファイル内での同名変数に引き継がれません。 どのようにすればよろしいでしょうか? ご存知の方、お願いします。

  • SolarisとLinuxのグローバル変数の扱いについて

    Solaris用のソースをLinuxで使えるように変更したいのですが、 グローバル変数について以下のようなことが発生していて困っています。 なにか、コンパイルオプションなどで対応はできないものでしょうか? Solaris (CC)では 特にextern宣言しなくても同じシンボルの外部変数はコモンセグメントに1つだけ作成しコンパイル自体は正常である。 しかし、Linux (g++)では externを宣言しないと同じシンボルを再定義したことになりエラーとなる。 これにより、グローバル変数を多用しているプログラムはLinuxでうまくコンパイルができない。 しかし、単純にextern宣言での対応は難しい。 extern宣言は外部で定義してあるグローバル変数を参照する というものだがLinux では 1つの定義を意外は全てexternしなければ、2重定義エラーになってしまう。 つまり、実体が1つであとはそれを参照しているという形でなければいけない。 ところが、その実体をどこにするか特定することができない。 例えば、gというグローバル変数を仮定する。 A.c,B.c,C.cはその3つのソースよりAA.aという静的ライブラリを構成する。 gはA.cで定義してありB.c,C.cはそれを参照する。 ところが C.cは個別にC.oというオブジェクトで他からの呼び出しがあり 別LMにリンクされる。 その時C.c内のgは実体を失うことになり未定義となる。 つまり、どれが実体になるかは何にリンクするかで決まるため 実態を特定できない。 また、共通のヘッダにグローバル変数が定義されている場合も、重複するというエラーを起こすため、 共通ヘッダからグローバル変数を分離し、何れかのソースにグローバル変数の実態を定義させる必要がある。 共通ヘッダを使っている他のソースはそのグローバル変数の実態を参照するようにexternの宣言をする。

  • 変数宣言・変数定義のちがいって??

    変数宣言・変数定義のちがいって?? 同じ意味なんでしょうか? 私の解釈では、 ・宣言っていうのは、今からこの変数を使いますよってことで。 ・定義っていうのは、実際に変数の領域をわりあてるってイメージなんですけど・・ なので、 int a; ←これは変数定義 extern int a; ←これは変数(extern)宣言 あってるでしょうか?

  • C言語のヘッダファイルの使い方

    ヘッダファイルの使い方について質問です。 ソースファイルA、ソースファイルBで共有して使用したい変数がある場合、 Aでは「int a」と宣言し、Bでは「extern int a」と宣言すれば 同じ変数を共有出来ると認識しています。 それをヘッダファイルへ記述しておきたい場合にはどのように 宣言しておけば良いのでしょうか? ヘッダファイルに「int a」と宣言した場合は両方のソースファイルで includeした時に多重定義でエラーとなります。 では「extern int a」と宣言しておいて、両方のソースファイルで includeするのが正しいのでしょうか? 初歩的な質問で申し訳ないですが、有識者の方、教えてください。

  • C++ visualstudio グローバル変数

    C++のプログラミングに関する質問です。 visual studio2008を使用しています。 手元に非常に複雑なC++ファイルなどから構成されている1つのprojectがあります。(ヘッダファイルなどもあります) そのため、このprojectをデバッグすると、A.cppファイルをデバッグ→B.cppファイルをデバッグ→A.cppファイルをデバッグ→C.cppファイルをデバッグのように、色々なcppファイルを跨ってデバッグします。 1つのcppファイルには大量の関数があり、cppファイルの先頭や,関数外の部分に例えばA.cppで int test などと宣言すれば、A.cppファイル内ではtestと名付けた変数をすべての関数で使えます。 しかし、あくまでA.cppファイル内だけで使用できるだけで、別のBやC.cpp内で使うことはできません。 このtest変数をB.cppやC.cppファイルでも使えるようにするにはどうすればいいでしょうか? 上で挙げた例でいうなら、A.cppからB.cppファイルに移動する際の関数の引数として渡す方法は考えられますが、実際には、 test変数を使いたいのはかなり後に登場するcppファイルで関数の引数として扱うのは非常に大変です。 (Z.cppでtest変数を使いたい。しかしZ.cppに到達するまでにはA~Y.cppを通り、その間に登場するすべての関数でtestを引数にしなければならない) 関数の引数でtest変数を使えるようにする以外の方法がありましたたら教えていただけると幸いです。 実際にやりたいことは A.cpp内にある関数が実行されたらその数をカウントし(A.cppのこの関数は何度も呼び出される関数) //count ++ このcount++の値によってZファイルのある関数での動作を変えたいと思っています。 if(count<100){ printf("aaa"); } しかし、現状ではZ.cppファイル内ではcountが定義されていないので上のようなif文を書くとエラーになってしまいます。

  • C言語のローカル変数の使い方について質問です。

    C言語の変数に関しての質問です。 グローバル変数を使わずに、関数内で宣言したローカルの変数を別のソースファイルで使用することって可能ですか? 例えば、a.cというソースファイルと、b.cというソースファイルがあります。 a.cの関数内で"FILE *fp;"と宣言したローカル変数を、b.cの関数内で共有して使うことはできるのでしょうか。 また、"fp"に直接アクセスはできなくても、間接的にアクセスできる方法があれば教えてください。 下に記述しているのは例え用に適当に書いたプログラムです。 --------------------- a.cのソースファイル --------------------- void Temp(void) { char file_name[128] = {}; errno_t error; FILE *fp; // ←この変数を別のソースで使いたいです scnaf_s("%s", file_name, 128); if(error = fopen_s(&fp, fname, "rb") != 0) { printf("ファイルがオープンできません"); return 0; } fclose(fp); } --------------------- b.cのソースファイル --------------------- void Temp2(void) { int size; // ここでa.cのTemp関数で宣言されている"fp"を使いたい fseek( fp, 0, SEEK_END ); fsize = ftell( fp ); fseek( fp, 0, SEEK_SET ); }

  • 変数はグローバルなんですか?

    初心者です。 関数sub xxx{  $abc=10; } 関数sub yyy{  $def=$abc } というように、関数xxxで宣言した変数もPerlでは 関数yyy内で参照できるのでしょうか。つまり、同じ ファイルにあれば関数内で宣言してもグローバル 変数として使用されるのでしょうか。 (my変数は除きます)

    • ベストアンサー
    • Perl

専門家に質問してみよう