
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 をつけた場合も、ファイルスコープ(こちらも、実際には、コンパイル単位内スコープ)となりますから、コンパイル単位の中の関数しかアクセスできません。そこで、コンパイル単位の中に、関数の実体がない場合に、質問されたような警告が出たのだろうと思います。

No.9
- 回答日時:
No.3 訂正です。
回答の中で使っている、
_GLOBAL_HERE
と、_ で始まるマクロは、よろしくないようです。
ということで、この部分、たとえば GLOBAL_HERE などにしてください。
訂正します。
さて、ご指摘がありまして、ありがとうございました。
そこまで、明文化されているとは知りませんでした。
失礼しました。
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なんじゃ……と思ったら、ベンダー独自の定義済みマクロを、_ + 大文字だったりするのですね。
もともとの気持ちは、「当社独自マクロ」だったのですが、少なくとも無条件にお勧めできる書き方ではないです。
No.6
- 回答日時:
ああそうだ, #2 では「プログラムを」って書いたけど, エラーメッセージも「正確に」書いてほしい.
余談ですが
Cにおけるグローバル変数は、「一カ所だけ宣言」「使うところですべて定義」という決まり
というのは「宣言」と「定義」が逆ではないかと>#3. あと, 「_+大文字英字」で始まる識別子もちょっと危険.
まあいずれにしてもソースファイル (とエラーメッセージ) が出てこないことには「群盲象をなでる」なわけですが. 特にこの場合には「[省略]」とされている部分が完全にわからないことにはそもそもプログラムとして成り立たないので, そんな状況では回答者がめいめいに勝手に想像するしかない.
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であれば、変数自体は作成されず、どこかにそのように変数があるものとしてコンパイルされます。リンク時に実際の変数と結びつくため、複数のソースで同じ変数が参照できます。
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が見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 競技プログラミングに関する質問です。 3 2022/04/03 19:51
- C言語・C++・C# C言語のファイル入力が分かりません 2 2022/05/22 06:35
- C言語・C++・C# メインプログラムに#include <algorithm>を書いて、 そのメインプログラムが // 3 2023/05/02 11:24
- Java javaでのプログラム(配列)について質問です. 2 2022/10/14 22:27
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 malloc関数を使ってください!お願いします! 最 1 2022/07/21 09:28
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# 至急お願いします。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分母 3 2022/07/19 17:09
- Java java 入力 3 4 3 出力 ABC DEFG HIJ このようなプログラムの書き方を教えてくだ 2 2022/07/15 14:18
このQ&Aを見た人はこんなQ&Aも見ています
-
C言語初心者の質問失礼します。
C言語・C++・C#
-
C言語での引数の省略方法
C言語・C++・C#
-
コンパイルエラーについて
C言語・C++・C#
-
-
4
C言語のポインターに関する警告
C言語・C++・C#
-
5
配列を含む構造体の初期値について
C言語・C++・C#
-
6
main.c:7:43: warning: implicit declaration of func
C言語・C++・C#
-
7
char*を初期化したいのですが
C言語・C++・C#
-
8
【gcc・cygwin】multiple definitionエラーの解決法
C言語・C++・C#
-
9
C言語のポインタに直接アドレスを割り振りしたい
C言語・C++・C#
-
10
コマンド(例えばls)の出力結果を文字列で取得するプログラムの作成方法
C言語・C++・C#
-
11
C言語 配列の長さの上限
C言語・C++・C#
-
12
read関数をノンブロッキングで実行する(c言語)
C言語・C++・C#
-
13
2重定義って??
C言語・C++・C#
-
14
エラーの意味は? Lvalue required
C言語・C++・C#
-
15
C言語でファイル読み書きを早くしたい。
C言語・C++・C#
-
16
C言語 ミリ秒を日付に変換には
C言語・C++・C#
-
17
至急です! マクロ定義で #define NUMBER 10とし 関数で max(double ma
C言語・C++・C#
-
18
VBA2005 16進を2桁で表示したい。
Visual Basic(VBA)
-
19
正負を反転させて出力するプログラム
C言語・C++・C#
-
20
ソケットのrecvの戻り値が0
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
1 つ以上の複数回定義されてい...
-
VBAを何回も作り直して、容量が...
-
エクセルVBAではRound...
-
” OS ビルド ” の意味が分か...
-
外部シンボル "_main"は未解決です
-
C言語でヘッダファイルにグロー...
-
ILSpyで、デコンパイルできない。
-
クリティカルエラー Expressio...
-
PRO*C コンパイルエラー
-
<math.h>があるのにsqrtが・...
-
ExcelVBAで『ByRef 引数の型が...
-
「fatal error C1189」を回避す...
-
複数のサブディレクトリを一緒...
-
VB6とInputManソフトの関係
-
「猫でもわかるプログラミング...
-
マクロ コンパイルがグレーバック
-
Visual C++ ヘッダー情報の反映
-
【VC++6.0(MFC)】警告「LINK : ...
-
ビルドから除外されたソースの...
-
「DeclareステートメントにPtrS...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBAを何回も作り直して、容量が...
-
” OS ビルド ” の意味が分か...
-
「fatal error C1189」を回避す...
-
C言語でヘッダファイルにグロー...
-
エクセルVBAではRound...
-
Makefile作成時の拡張子.oとは?
-
ILSpyで、デコンパイルできない。
-
1 つ以上の複数回定義されてい...
-
マクロ コンパイルがグレーバック
-
セミコロンについて
-
外部シンボル "_main"は未解決です
-
C++コンパイル時に『 C1083: in...
-
ビルドとリビルドの違いを教え...
-
コンパイルエラー:ユーザ定義...
-
「DeclareステートメントにPtrS...
-
戻り値について
-
pyc 編集 閲覧
-
PRO*C コンパイルエラー
-
【VC++6.0(MFC)】警告「LINK : ...
-
漢字のコメントをはずすとコン...
おすすめ情報