C言語でヘッダファイルにグローバル変数を宣言する方法と注意点

このQ&Aのポイント
  • C言語でヘッダファイルにグローバル変数を宣言する方法を説明します。
  • 静的グローバル変数はソースファイル内で宣言する必要があります。
  • ヘッダファイル内で変数を宣言すると警告が表示される場合があります。
回答を見る
  • ベストアンサー

C言語でヘッダファイルにグローバル変数を宣言する

main.hに static int a; と記述し、main.cで #include "main.h" [省略] a=10; のように使用して、-Wallをつけてコンパイルすると、main.cで使用しているにも関わらず、 'a' defined but not used という警告が表示されます。 同様に、関数においても、ヘッダファイルでstaticをつけると ‘~’ declared ‘static’ but never defined と警告されます。 静的グローバル変数などは、ソースファイル内で宣言しなければいけないのでしょうか?ヘッダファイル内で宣言しても警告が出ないような方法はありますか?

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

  • ベストアンサー
回答No.3

静的なグローバル変数というのがそもそもおかしい気がしますが。(もしかしたら、static を「静的」と直訳したのかな?) そもそも、関数の外で定義されたグローバル変数は、性格的に静的です。 プログラムの実行時に生成されてその後プログラムの終了時までそのまま生存し続けますから。 関数の外で static 宣言された変数は「ファイルスコープ」を持ちます。 ※一般的には、「ファイルスコープ」という呼び方はされますが、実際には、「コンパイル単位」からは見えるのは、No.2で指摘されているとおり。 なので、複数のファイルからアクセスするための変数=グローバル変数 に、static をつけることはまずありません。 さて、質問の内容から判断すると、 ・最初、static をつけずに、ヘッダファイルでグローバル変数を定義しようとしたら、リンクで失敗した。 ・この時点で、質問の、[省略]の部分で、グローバル変数を定義して、それが生き残っている。 ・何かの拍子に、ヘッダファイルのグローバル変数に、static をつけてみたら、リンクも成功してしまった。 という流れが見える気がするのですが。 そもそも、Cにおけるグローバル変数は、「一カ所だけ宣言」「使うところですべて定義」という決まりなので、ちょっと管理がやっかいです。 こういう流れを仮定して、ヘッダファイルに普通にグローバル変数を定義するのに、よく使われていた方法は、 ---- main.h --- #if defined(_GLOBAL_HERE) #define GLOBAL #else #define GLOBAL extern #endif GLOBAL int a; ----- ここまで ---- というヘッダファイルを作って、 main.c では、 #define _GLOBAL_HERE #include "main.h" その他のファイルでは、 #include "main.h" で、main.c では、extern なし、それ以外のファイルでは、 extern つきの変数宣言に差し替えるという手法があります。 初期化を含む場合は、 ---- main.h --- #if defined(_GLOBAL_HERE) #define GLOBAL #define DEF(x) = (x) #else #define GLOBAL extern #define DEF(x) #endif GLOBAL int a; GLOBAL int b DEF(1); ----- ここまで ---- とか。 (ただし、この DEF() は万能ではないです) あと、関数で static をつけた場合も、ファイルスコープ(こちらも、実際には、コンパイル単位内スコープ)となりますから、コンパイル単位の中の関数しかアクセスできません。そこで、コンパイル単位の中に、関数の実体がない場合に、質問されたような警告が出たのだろうと思います。

その他の回答 (8)

回答No.9

No.3 訂正です。 回答の中で使っている、 _GLOBAL_HERE と、_ で始まるマクロは、よろしくないようです。 ということで、この部分、たとえば GLOBAL_HERE などにしてください。 訂正します。 さて、ご指摘がありまして、ありがとうございました。 そこまで、明文化されているとは知りませんでした。 失礼しました。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.8

>main.cで使用しているにも関わらず >'a' defined but not used main関数のなかにローカル変数としてaが存在してたりするのでは? >静的グローバル変数などは、ソースファイル内で宣言しなければいけないのでしょうか? そもそも、変数や、関数の実体(定義)をヘッダに書くべきではない。 「定義」と「宣言」がごっちゃになっていないでしょうか? >ヘッダファイル内で宣言しても警告が出ないような方法はありますか? ヘッダファイルには宣言を行い、ソースファイルに定義を書く。 ---main.h--- extern int a; ---main.c--- int a; ------------ 他の方も書かれていますが、そもそもグローバル変数は静的記憶期間を持つので、 staticをつける意味はさほどありませんし、明示的に使用するにしても、 その使用はソースファイル内で限定されて、行われるべきものです。 蛇足ですが。。。 >あと、_ + 大文字は、Cの定義済みマクロは、__ (_ 2個)で始まるからOKなんじゃ…… >と思ったら、ベンダー独自の定義済みマクロを、_ + 大文字だったりするのですね。 ベンダーではなくて、C言語の規格上で処理系における、 予約済み識別子の定義が許可されているからで、 問題なのは、予約済み識別子をマクロとして定義した場合は、 動作が未定義とされているところです。 予約済み識別子の定義として以下が 規定されています。 以下、X3010抜粋 予約済み識別子 ・下線に続き大文字1文字または、下線に続きもう一つ下線で始まるすべての識別子は、  いかなる使用に対しても、常に予約済みとする。 ・一つの下線で始まるすべての識別子は、通常の名前空間およびタグ名前空間の双方における  ファイル有効範囲をもつ識別子としての使用に対して、常に予約済みとする。 ・#他にもいくつかありますが、今回は割愛。 予約済み識別子以外でプログラムが、識別子を宣言・定義し、その文脈において 識別子が予約済みである場合または、予約済みの識別子をマクロとして定義した場合、 その動作は未定義とする。 #まぁ、被らないような名前にして置けば、実害はほとんどありませんが:p

回答No.7

No.3です。 呼ばれたような気がしたので……。 「定義」と「宣言」が逆でした。 ・一カ所だけ「定義」(実体があるもの) ・使うところでは、「宣言」(名前だけで実体のないもの) でした。 あと、_ + 大文字は、Cの定義済みマクロは、__ (_ 2個)で始まるからOKなんじゃ……と思ったら、ベンダー独自の定義済みマクロを、_ + 大文字だったりするのですね。 もともとの気持ちは、「当社独自マクロ」だったのですが、少なくとも無条件にお勧めできる書き方ではないです。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.6

ああそうだ, #2 では「プログラムを」って書いたけど, エラーメッセージも「正確に」書いてほしい. 余談ですが Cにおけるグローバル変数は、「一カ所だけ宣言」「使うところですべて定義」という決まり というのは「宣言」と「定義」が逆ではないかと>#3. あと, 「_+大文字英字」で始まる識別子もちょっと危険. まあいずれにしてもソースファイル (とエラーメッセージ) が出てこないことには「群盲象をなでる」なわけですが. 特にこの場合には「[省略]」とされている部分が完全にわからないことにはそもそもプログラムとして成り立たないので, そんな状況では回答者がめいめいに勝手に想像するしかない.

  • pyonmae
  • ベストアンサー率64% (40/62)
回答No.5

こんにちは。 aを使用しないmain.c以外のソースでも、main.hをインクルードしているためと思われます。 例えば、main.c以外に"sub.c"というソースがあり、この2つをコンパイルしリンクする事になっているとします。 cc -Wall main.c sub.c などとしてビルドすると、main.cの方はワーニングなしですが、sub.cでは恐らくaを使用していないため、コンパイル時に引っかかるのではないでしょうか。 いやいやmain.cだけだよと言うのなら、もう何も言う事はありませんが・・・。

回答No.4

> ヘッダファイル内で宣言しても警告が出ないような方法はありますか? 警告が出ないように、変数を使用すればいいだけです。 例えば、main.cとtest.cでmain.hをインクルードしているとすると、aという変数はmain.cとtest.cの両方に存在します。そして、これらは同じものではありません。 よって、main.cでaを使用していても、test.cの方で使用していなければ、警告が出ます。 ヘッダーに限らず、#includeでインクルードした場合、そのファイル内の記述はソースに直接書かれているのと同じ効果があります。なので、main.hをmain.cとtest.cでインクルードすると、 [main.c] static int a; ... [test.c] static int a; ... という記述と同じと解釈されます。同じ変数名でも、関数が違えば別物として扱われるように、aもソースが違えば別物として扱われてしまいます。 そのため、通常はヘッダーにはexternで記述しておき、変数の実体は1つのソースで宣言することが多いのです。externであれば、変数自体は作成されず、どこかにそのように変数があるものとしてコンパイルされます。リンク時に実際の変数と結びつくため、複数のソースで同じ変数が参照できます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

そんなあほな規定はない>#1. これだけでは原因を判断できないので, プログラム全体を見せてください. もっとも, 「static な変数や関数」をヘッダで宣言 (and/or 定義) する必要性は思いつかないのだが.

回答No.1

"static"を利用しているためです。 "static" は,関数内で使用される場合,同じ関数が実行される限り同一のメモリに割り当てられるですが, 関数外で使用される場合は,同一ファイル上からのみ参照できるという意味になります。 main.hに"static int a;"としているので,"a"はmain.h内でのみ参照できることになります。 つまり,main.cからはアクセス出来ません。 main.hで宣言をしたい場合は,"int a;"としましょう。 どうしても,"static"を使用したい場合は, main.cのなかに記述して下さい。

関連するQ&A

  • C言語でヘッダファイルを自作する

    C言語で#defineを用いてヘッダファイルを作成したのですが、 作成したコンパイルするときにヘッダファイルがオープンできません。 参考にしている資料があるのですが、そこに書かれているサンプルプログラムを 丸ごとコピーして作ったプログラムも同様にヘッダファイルがオープンできない というエラーが出るので、ヘッダファイルを定義する方法そのものが間違っていると 思うのですが、どこが間違っているのでしょうか? よろしければ正しい記述方法もお教えください。 #include <stdio.h> #if !defined SAMPLE_H #define SAMPLE_H wa(int a, int b) { return a+b; } #endif #include "sample.h" int main(){ printf("%d\n",wa(40,70)); return 0; } ヘッダファイルの定義の方法は他にもあるとは思いますが、 今回は#defineを用いた方法でお願いします。

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

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

  • ヘッダファイルとは?

    ヘッダファイルを作って、そこに構造体を送りたいのですが、 「引数宣言は 'data' で始められない」というエラーがヘッダファイル側で起きてしまいます。 main()で作ったからいけないのでしょうか? 分かる方教えていただけませんか? #include<stdio.h> #include "Max_Score.h" /*構造体の宣言*/ typedef struct data{ ・・・・・; }DATA; void main(){ DATA data[50]; ・・・・・・・・; Max_Score(data); } /*Max_Score()側*/ void Max_Score(data *p){ ・・・・・; }

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

    前回のC言語のコンパイラの質問で、たくさんのご回答ありがとうございました。 おかげさまでコンパイラはなんとかなりそうですが、ひょっとしたらまた同じ質問を載せるかもしれません(^^; 今回はC言語のヘッダファイルを自分で作ってみたいんですが、よくわかりません。 microsoft visual studioのvisual c++付属のINCLUDEフォルダにある、stdio.hを開いてみたのですが、基本のprintf()やscanf()なども、どう定義されているか わからず終いでした。本などでもいまいち詳しく書いていなく(そう思うのは僕だけ?)、困っています。c言語のヘッダファイルとc++のヘッダファイルは やっぱり別ものなんでしょうか?ご回答おまちしております。

  • C言語のヘッダーファイルについて

    宜しくお願い致します。 C言語について殆ど知識が無い為、変な質問でしたらすみません。 あるソースをビルドしてみたのですが、エラーが出てしまいます。 fatal error C1083: インクルード ファイルがオープンできません。'ヘッダーファイル名': No such file or directory このエラーが出るのは、以下のファイルです。 <sys/socket.h> <netdb.h> <netinet/in.h> <sys/param.h> <sys/uio.h> <unistd.h> これらのファイルは一体何処にあるのでしょうか。 どうすればこのエラーは消えるのでしょうか・・・

  • C言語のヘッダーファイルの作成方法

    Cの初心者です、宜しくお願いします。 下のようなヘッダを作成して、別のファイルに#includeして、走らせて見ました。 そこで疑問点ですが、 「mm」については置き替えが出来て、計算処理をしているのですが、「mm」の型宣言をしていません、これでもエラーにならないのは何故でしょうか。 普通に「mm」という変数とした場合(「mm」をヘッダーとして#includeしなかった場合)にはint型を宣言していないとエラーになると思うのですが。 また、「hh」については、そのまま「hh」がprintfされています。 文字の場合の置き替えは、使えないということでしょうか。 宜しくお願いします。 /*header_2.h*/ #define hh HEADER練習 #define mm 100 ================================================ #include "header_2.h" int main(void) { int aaa = 50 ; printf("%d\n\n" , mm); printf("hh"); printf("%d\n\n" , mm * 100); printf("%d\n\n" , mm * aaa); return 0; }

  • ヘッダファイルでのFILE型引数宣言について

    下記の(1)、(2)のファイルについての質問になります。 (1)cファイル #include <stdio.h> /******************/ /* 表示モード処理 */ /******************/ void view_mode( FILE *fp_in ) ^^^^ { char data; while( 1 ){ /* ファイルから1文字読込み */ data = fgetc( fp_in ); /* ファイルの終了かをチェック */ if(data == EOF ){ break; } /* 表示処理 */ printf( "%c", data ); } return; } (2)ヘッダファイル void view_mode( FILE *fp_in ); ^^^^ ◆質問内容 (1)にview_modeの処理を書き、(2)にview_modeのプロトタイプ宣言をしていますが、 (1)はコンパイルが通るのですが、(2)はコンパイルが通りません。 エラー内容を見ると、 エラー E2147 testddga.c 1: 引数宣言は 'FILE' で始められない と表示されてしまいます。 (1)では、引数宣言にFILEを使用しているのにコンパイルが通り、 (2)では、何故かはコンパイルが通らないので、疑問に思っております。 お手数ですが、ご教授の程お願いたします

  • C言語 プロトタイプ宣言

    分割コンパイルした場合のプロトタイプ宣言について質問です。 以下のプログラムをコンパイルすると警告がでます。 プロトタイプ宣言は関数を利用する側と定義側両方に必要と理解していたのですが・・・ どなたか教えていただけますでしょうか。 windows7 cygwin gccでコンパイル エラーメッセージ $ gcc -o testMain.exe testMain.c testKioku.c testKioku.c:9: 警告: conflicting types for 'func1' testKioku.c:3: 警告: previous declaration of 'func1' was here testKioku.c:17: 警告: conflicting types for 'func2' testKioku.c:4: 警告: previous declaration of 'func2' was here ソース testMain.c #include <stdio.h> void func1(void); void func2(void); int cnt=5; main(){ printf("main=%d\n",cnt); func1(); func2(); } testKioku.c #include <stdio.h> void func1(void); void func2(void); extern int cnt; func1() { cnt++; printf("func1 global cnt=%d\n",cnt); func2(); } func2() { printf("func2 global cnt=%d\n",cnt); }

  • linuxにおけるCの自作ヘッダファイル

    現在C言語のしっかりと学ばなかった部分を学習したいと思い、自作ヘッダファイルの作成を勉強しています。 そこで、書籍のその章を一通り読んだあと、自分で簡単なものを作成してみましたが、エラーが出てうまくいきません。 どうしてかわかる方いたら教えてください。 コード *****main.c***** #include "print.h" int main(void) { print(); return 0; } *****print.c***** #include <stdio.h> void print(void) { printf("test\n"); } *****print.h***** extern void print(void); エラー /tmp/ccH551c1.o: In function `main': /home/ユーザ名/Documents/StudyC/main.c:5: undefined reference to `print' collect2: ld returned 1 exit status CentOS6.6にて端末上での実行です。 自分の解釈では、""でincludeすることでカレントディレクトリから目的のヘッダファイルを見つけ出してインクルードする、また、ヘッダファイル内でexternすることによってprint.cから目的の関数を定義しているので、main.cでは問題なく使えると思っています。 しかし、エラーではprint()が定義されていないと出るのでまったくわかりません・・・。

  • ヘッダーファイルでは、他のヘッダーファイルをインクルードできないのか

    Javaを仕事で使っています。 最近趣味でC++を始めました。色々形式の違いに戸惑っています。 C++では関数を宣言しなければならないので、クラス名と同じヘッダーファイルにそのクラスで使う関数を宣言して、それをインクルードしています。 そこで今、壁にぶちあたりました。 あるクラス(仮にFooとします)の関数で、他のクラス型(Hogeとします)を引数に取りたいので、ヘッダーファイルにそれを宣言しようとしているのですが、コンパイルエラーになってしまいます。 Foo.hは以下のような感じ。 #include Hoge.h 中略 GetHoge(Hoge hoge); コンパイルエラーでは error C2011: 'Hoge' : 'class' 型の再定義 などと言われます。 クラスとその同名のヘッダーファイル、という形式を変えずに 他のクラス型を引数にとる関数を作るには、どうしたらよいのでしょうか? C++に関しては全くの素人です。詳しい方、ご教示願います。

専門家に質問してみよう