C++のconstについて
解決済
回答 3
投稿
- 評価
- クリップ 0
- VIEW 3,819
C++のconstについてです。
以下の1つのヘッダと、2つのcppがあるとします。
そして、2つのcppは、以下のヘッダファイルを
それぞれ、別途インクルードしているとします。
----- test.h -----
const int g_Test = 0;
------------------
----- a.cpp -----
...
#include "test.h"
...
void FuncA()
{
printf("g_Test = %d\n", g_Test);
}
...
-----------------
----- b.cpp -----
...
#include "test.h"
...
void FuncB()
{
printf("g_Test = %d\n", g_Test);
}
...
-----------------
この場合、C++においては、
const int g_Test = 0;
のように、constがついているものについては
内部結合として、扱われるかと思います。
ここで疑問があるのですが、g_Testは、
a.cppとb.cppで、それぞれインクルードされて
利用されていますが、
内部結合なので、a.cppとb.cppのそれぞれの中で、
別々に、変数の領域が確保されるような気がしました。
しかし、ネット上で検索しても、明確な記述は
今のところ見つかっておりません。
試しに、手元のVisualStuidio2008でいろいろと
調べていたのですが、以下ようにマクロを利用した場合の
mapファイルを比較してみたところ、
----- test.h -----
#define g_Test (0)
------------------
mapファイルの中の.rdataや.bssが、const変数の場合も、
マクロの場合も同じでしたので、もしかしたら、
マクロと同等な扱いを受けているような気もしてきました。
ちなみに、constを外して
----- test.h -----
int g_Test = 0;
------------------
とすると、グローバル変数になるので、
ビルドエラーが出るようです。
ということで、
const int g_Test = 0;
と書かれたファイルを、それぞれ別のcppで
インクルードした場合について、
変数領域の確保がどうなっているか?、
マクロと同等のものとして扱われるか?、
といった点についてご存知でしたら、ご教示頂けないでしょうか?
お手数をおかけいたしますがどうぞよろしくお願い致します。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
こんにちは。
C++でconstつけたら、内部リンケージになることは知りませんでした。constだけでは外部リンケージなので、通常はstaticも付けないといけないと思ってました。
調べてみたら、内部結合と外部結合にて、C++はconstだけで内部リンケージになり、Cはstaticもつけないと内部リンケージにならないそうです。びっくり。
内部結合なので、a.cppとb.cppのそれぞれの中で、別々に、変数の領域が確保されるような気がしました。
文法上はその通りと思います。同じ値がコード領域に定義された場合、最適化して1つにしてしまうようなリンカもあるようです。(確認したことはないですが。)
マクロと同等のものとして扱われるか?、
これは異なります。マクロはプリプロセッサが文字列的に置き換えてしまうため、objファイル内のシンポル・テーブルへ出力されません。その結果、IDE等でポイントしても置き換え前の文字列が表示されることはないです。
しかし、constで宣言した場合は、シンポル・テーブルへ出力されIDEにて表示されます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
C++でもそうですが、言語の規格は、「どのように動く」かを定義するもので、「それをどのように実装すべきか」は、必要がなければ規定していません。
で、「const int
が内部結合」ということは、「この変数は当該ファイル外からは使われ得ない」ということになります。
const volatile
で最適化が阻止されているとか、ポインタを取るので実体の伴った変数として必要ということでなければ、この変数の代わりに直接値を書いても何も問題ありません。つまり、ファイル内を一通り見て最適化するとまずい使い方がなければ、定数として畳み込んでしまっても動作は全く同じです。変数として領域を確保するまでもありません。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
内部結合なので、a.cppとb.cppのそれぞれの中で、
別々に、変数の領域が確保されるような気がしました。
VC++では実際にそうなります。一応確認のため複数のソースに分けて書いた関数で変数のポインタを表示させたところ、それぞれ異なるアドレスになっていました。
ちなみに、const int g_Test = 0;
とstatic const int g_Test = 0;
でアセンブリソースを出力して比較しましたが、VC++では全く同じコードでした。
マクロと同等のものとして扱われるか?、
全く別物です。マクロは単なるテキストの置き換えですが、constグローバル変数は厳密に型を持った読み取り専用の変数として扱われます。
const付きのグローバル変数は、領域へのアクセス(ポインタ経由の参照など)を行わずに値を利用するだけなら、コンパイラーが使用箇所で数値に置き換えます。その場合、領域が確保されることもないので、結果的にはマクロで書いたのと同じような振る舞いに見えます。
ただし、単純な数値の置き換えができないような非組み込み型の場合は領域が確保されます。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/05/20 22:14
大変参考になりました。
また、私も今回、C++のconstの内部結合と外部結合を知って、少し驚いておりました。
ところで、別々のcppでインクルードされても、リンカによって最適化されるなら
問題はないのですが、もし、それぞれの変数の領域が確保されるなら、
無駄な領域が増えていくので、あまりよくなさそうには思いました。
なので、この点について、詳細を知りたいと思っておりました。
あと、確かにマクロとは違うかと思います。
ただ、どこかで見かけたのですが、const変数として宣言されている場合、
C++は、場合によっては、変数領域を確保しないみたいな記述が
あったような気がします。
再度ネット上を検索したのですが、見つかりませんでした。
なので、こういった点をもう少しクリアにできればと思っておりました。
2016/05/20 22:33 編集
この場合は、異なる領域を確保されているということです。
しかし、これってシュレディンガーの猫のようです。
アドレスを表示しているa.exeをnmコマンドでみたところ、__ZL6g_Testというシンボルが2つ出力され、表示されたアドレスと同じ値が割り当てられていました。
しかし、値を表示するだけでアドレス表示をやめると、nmコマンドで出力されなくなりました。つまり、領域が割り当てられていないようです。
> もし、それぞれの変数の領域が確保されるなら、無駄な領域が増えていくので、あまりよくなさそうには思いました。
正直、誤差と思います。もし、配列で巨大な領域を確保するのでしたら、明示的に同じ領域を使うべきと思います。普通にconst変数として定義するのであれば、1,000個2,000個のような数の定義はなかなか厳しいものがあります。そして、仮に10,000個定義したとしても高々40KBytesです。
もし、組み込み系でそのような贅沢が許されない場合は、extern宣言等を使って領域を確実に1つしか消費しないようにするのが妥当と思います。
2016/05/21 13:56
変数のアドレスを表示していると、異なる領域が確保されるが、
アドレス表示をやめると、コンパイラが領域確保が必要ないと
判断して、領域確保をしないということですよね。
つまり、const変数の使用状況によって、領域が確保されたり
されなかったりする、ということだと思います。
また、誤差の範囲にすぎないという点も大変参考になりました。
確かに微々たるものではあるかと思います。
今までの仕事では、どちらかというと組み込み系的な仕事が
最初は多かったので、マクロではなくて、const変数で
それぞれのcppに領域が確保されそうなことに
違和感を感じたのですが、今後は、プラットフォームや
作業のしやすさなどを考慮して、マクロやconstの利用を
決めて行ければと思っております。
ご教示ありがとうございました。