-PR-
締切済み

ヘッダファイルにおける文字列リソース定義

  • 暇なときにでも
  • 質問No.296036
  • 閲覧数2444
  • ありがとう数6
  • 気になる数0
  • 回答数4
  • コメント数0

お礼率 50% (8/16)

C言語(主にVC++)で開発をしていると、よく、

const char MSG_HELLO[] = "HELLO!";

のように、ヘッダファイル中で、文字列リテラルを定義します。
自分もいつのまにかこのようにリソース定義するようになっていましたが、初期の頃から疑問だったのは、extern宣言せずにchar配列を宣言しているから、コンパイラが最適化しなかったら、上記宣言のあるヘッダファイルを読み込んで、その定義を使った個所のあるソース分文字列リテラルがメモリ上に確保されてしまうのではないか、、?ということです。
つまり、本来なら

const char* MSG_HELLO[] = "HELLO!";

とソースファイル中で定義し、ヘッダファイルには

extern const char* MSG_HELLO;

とすべきではないか、と思うわけです。ただ実際にこれをやっているとヘッダとソースの両方のメンテナンスが必要になるので、冒頭のように記述しているのだと思いますが。
この、本来なら下記のようにすべきだが、コンパイラの最適化(リソースのプール)を期待して最初のように書いている、という解釈は正しいでしょうか?
通報する
  • 回答数4
  • 気になる
    質問をブックマークします。
    マイページでまとめて確認できます。

回答 (全4件)

  • 回答No.1
レベル12

ベストアンサー率 40% (201/496)

回答ではないですが...
#最近のコンパイラ・リンカの事情には詳しくはないので

少なくとも、コンパイラの最適化ではないですよね。コンパイラはオブジェクトを作り、その中に "HELLO!"分の領域はどのオブジェクトにもあると思います。

リンカが最適化によって上記領域をまとめるか否かはよくわかりません。私の認識では、ロードモジュールになったときにも別の領域になっていると考えてます。#リンクマップを見ればわかるのかな?

メンテナンス性という意味で、#define と #ifdefを組み合わせればそれほど苦では無いと思います。量が多ければ大変ですが...。VCなら rcに文字列をまとめた方が行儀がよいのかもしれませんね。#私はやってませんが...^^;)
お礼コメント
akubiII

お礼率 50% (8/16)

たしかにコンパイル完了時点では、各オブジェクトファイル内に各文字列オブジェクトがあり、リンク時にまとめられるのでしょうね、、私もそのあたりもう少し勉強しなければ。
ファイル冒頭で#ifdefで区切っても各オブジェクトファイルでオブジェクトが確保される点は変わらないと思います、、
ご回答ありがとうございました。
投稿日時 - 2002-06-26 08:38:51


  • 回答No.2
レベル14

ベストアンサー率 65% (1020/1553)

私ならリテラル文字列はヘッダファイルで
#define
か、リソースです。

ちなみに、C++でヘッダファイル中に
const char* MSG_HELLO[] = "HELLO!";
を書くとリンクでエラーになったような・・・
お礼コメント
akubiII

お礼率 50% (8/16)

#defineで区切ると、各部に文字列リテラルが直接埋め込まれてしまうので、コンパイラの最適化がないとそれこそ大変なことになる気がして使っていません。
たしかにQuickCでやっていた頃は、ヘッダで定義するとエラーになった記憶があります。このあたりはtoysmithさんがお答えになっている通りなのでしょうね、、
ご回答ありがとうございました。
投稿日時 - 2002-06-26 08:41:43
  • 回答No.3
レベル13

ベストアンサー率 37% (570/1525)

ANSI以前のC言語において「外部リファレンスを持つ変数オブジェクト」の領域は『あいまいなDEF/REF規約』によって規定されていました。

あいまいなDEF/REF規約とは「定義(Define)と参照(Reference)が明確に分離していない」ということで、
・ブロック外定義の変数/配列は記憶クラスを省略するとexternとなる
・複数のextern宣言された変数/配列オブジェクトが存在する場合、1つの実態が確保される
という規約によって正当化されます。
結果、ご質問のようなコードはリンカによって1つの実体オブジェクトになることが保証されていました。

しかし、現在のC言語規約では「明確なDEF/REF規約」が用いられているため、ブロック外で記憶クラスを省略した同一名称の変数/配列オブジェクトを複数宣言することは推奨されません。
「明確なDEF/REF規約」に準拠した処理系ではリンカエラーになります。
「あいまいなDEF/REF規約」をサポートした処理系ではワーニングが発生した上で、ANSI以前のCコンパイラと同様の配置を行います。

static記憶クラスで宣言していない限り、同一名称の変数/配列オブジェクトが複数配置されることは(外部リファレンスを持つオブジェクトでは)ありえません。
お礼コメント
akubiII

お礼率 50% (8/16)

なるほど、、そういう規約があったんですね。ではVCはあいまなDEF/REF規約をサポートしているんですね、、
ということはやはり最新の仕様ではヘッダファイルで文字列リテラルを定義するのは望ましくないと思うのですが、では実際どのようにすればいいのでしょう、、yatokesaさんがご指摘の通りVCではリソースファイルのストリングテーブルを使うのが望ましいかもしれませんが、プラットフォーム依存になってしまう点と、rcファイルは扱いにくい(リソースエディタを開くのも面倒)という点から、つかっていません。やはりヘッダとソースにわけるのが正しいのでしょうか、、これもメンテナンスが大変になるので避けたいのですが、、
なお質問中の
const char* MSG_HELLO[] = "HELLO!";

onst char* MSG_HELLO = "HELLO!";
と訂正させて頂きます。
ご回答ありがとうございました。
投稿日時 - 2002-06-26 08:46:38
  • 回答No.4
レベル12

ベストアンサー率 40% (201/496)

>ファイル冒頭で#ifdefで区切っても各オブジェクトファイルでオブジェクトが確保される点は変わらないと思い ます、、

#ifdef __MAIN__
const char* MSG_HELLO = "HELLO!";
#else
extern const char* MSG_HELLO;
#endif

mainのあるソースのみ #define __MAIN__ のようにする。オブジェクトは1つで済みますよね?
私の常套手段です。が、これが増えてくるとメンテナンスが大変になってきますが...。
お礼コメント
akubiII

お礼率 50% (8/16)

なるほど、、! これはアイデアですね。
参考にさせて頂きます。
ソースとヘッダにわける以外では、最善策かもしれませんね、、悩ましいです
投稿日時 - 2002-06-26 12:49:08
このQ&Aで解決しましたか?
関連するQ&A
こんな書き方もあるよ!この情報は知ってる?あなたの知識を教えて!
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。

その他の関連するQ&A、テーマをキーワードで探す

キーワードでQ&A、テーマを検索する
-PR-

特集


開業・独立という夢を持つ人へ向けた情報満載!

ピックアップ

ページ先頭へ