質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

6614閲覧

C++のconstについて

aoshanghai

総合スコア24

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/05/20 12:23

C++のconstについてです。

以下の1つのヘッダと、2つのcppがあるとします。
そして、2つのcppは、以下のヘッダファイルを
それぞれ、別途インクルードしているとします。

C++

1----- test.h ----- 2const int g_Test = 0; 3------------------ 4 5----- a.cpp ----- 6... 7#include "test.h" 8... 9void FuncA() 10{ 11 printf("g_Test = %d\n", g_Test); 12} 13... 14----------------- 15 16----- b.cpp ----- 17... 18#include "test.h" 19... 20void FuncB() 21{ 22 printf("g_Test = %d\n", g_Test); 23} 24... 25-----------------

この場合、C++においては、
const int g_Test = 0;
のように、constがついているものについては
内部結合として、扱われるかと思います。

ここで疑問があるのですが、g_Testは、
a.cppとb.cppで、それぞれインクルードされて
利用されていますが、
内部結合なので、a.cppとb.cppのそれぞれの中で、
別々に、変数の領域が確保されるような気がしました。

しかし、ネット上で検索しても、明確な記述は
今のところ見つかっておりません。

試しに、手元のVisualStuidio2008でいろいろと
調べていたのですが、以下ようにマクロを利用した場合の
mapファイルを比較してみたところ、

C++

1----- test.h ----- 2#define g_Test (0) 3------------------

mapファイルの中の.rdataや.bssが、const変数の場合も、
マクロの場合も同じでしたので、もしかしたら、
マクロと同等な扱いを受けているような気もしてきました。

ちなみに、constを外して

C++

1----- test.h ----- 2int g_Test = 0; 3------------------

とすると、グローバル変数になるので、
ビルドエラーが出るようです。

ということで、
const int g_Test = 0;
と書かれたファイルを、それぞれ別のcppで
インクルードした場合について、
変数領域の確保がどうなっているか?、
マクロと同等のものとして扱われるか?、
といった点についてご存知でしたら、ご教示頂けないでしょうか?

お手数をおかけいたしますがどうぞよろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

こんにちは。

C++でconstつけたら、内部リンケージになることは知りませんでした。constだけでは外部リンケージなので、通常はstaticも付けないといけないと思ってました。
調べてみたら、内部結合と外部結合にて、C++はconstだけで内部リンケージになり、Cはstaticもつけないと内部リンケージにならないそうです。びっくり。

内部結合なので、a.cppとb.cppのそれぞれの中で、別々に、変数の領域が確保されるような気がしました。

文法上はその通りと思います。同じ値がコード領域に定義された場合、最適化して1つにしてしまうようなリンカもあるようです。(確認したことはないですが。)

マクロと同等のものとして扱われるか?、

これは異なります。マクロはプリプロセッサが文字列的に置き換えてしまうため、objファイル内のシンポル・テーブルへ出力されません。その結果、IDE等でポイントしても置き換え前の文字列が表示されることはないです。
しかし、constで宣言した場合は、シンポル・テーブルへ出力されIDEにて表示されます。

投稿2016/05/20 13:04

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aoshanghai

2016/05/20 13:14

ご回答ありがとうございます。 大変参考になりました。 また、私も今回、C++のconstの内部結合と外部結合を知って、少し驚いておりました。 ところで、別々のcppでインクルードされても、リンカによって最適化されるなら 問題はないのですが、もし、それぞれの変数の領域が確保されるなら、 無駄な領域が増えていくので、あまりよくなさそうには思いました。 なので、この点について、詳細を知りたいと思っておりました。 あと、確かにマクロとは違うかと思います。 ただ、どこかで見かけたのですが、const変数として宣言されている場合、 C++は、場合によっては、変数領域を確保しないみたいな記述が あったような気がします。 再度ネット上を検索したのですが、見つかりませんでした。 なので、こういった点をもう少しクリアにできればと思っておりました。
Chironian

2016/05/20 13:35 編集

MinGW(gcc)で、g_Testのアドレスを表示してみたら、a.cppとb.cppで異なるアドレスが表示されました。 この場合は、異なる領域を確保されているということです。 しかし、これってシュレディンガーの猫のようです。 アドレスを表示しているa.exeをnmコマンドでみたところ、__ZL6g_Testというシンボルが2つ出力され、表示されたアドレスと同じ値が割り当てられていました。 しかし、値を表示するだけでアドレス表示をやめると、nmコマンドで出力されなくなりました。つまり、領域が割り当てられていないようです。 > もし、それぞれの変数の領域が確保されるなら、無駄な領域が増えていくので、あまりよくなさそうには思いました。 正直、誤差と思います。もし、配列で巨大な領域を確保するのでしたら、明示的に同じ領域を使うべきと思います。普通にconst変数として定義するのであれば、1,000個2,000個のような数の定義はなかなか厳しいものがあります。そして、仮に10,000個定義したとしても高々40KBytesです。 もし、組み込み系でそのような贅沢が許されない場合は、extern宣言等を使って領域を確実に1つしか消費しないようにするのが妥当と思います。
aoshanghai

2016/05/21 04:56

コメントありがとうございます。 変数のアドレスを表示していると、異なる領域が確保されるが、 アドレス表示をやめると、コンパイラが領域確保が必要ないと 判断して、領域確保をしないということですよね。 つまり、const変数の使用状況によって、領域が確保されたり されなかったりする、ということだと思います。 また、誤差の範囲にすぎないという点も大変参考になりました。 確かに微々たるものではあるかと思います。 今までの仕事では、どちらかというと組み込み系的な仕事が 最初は多かったので、マクロではなくて、const変数で それぞれのcppに領域が確保されそうなことに 違和感を感じたのですが、今後は、プラットフォームや 作業のしやすさなどを考慮して、マクロやconstの利用を 決めて行ければと思っております。 ご教示ありがとうございました。
guest

0

内部結合なので、a.cppとb.cppのそれぞれの中で、
別々に、変数の領域が確保されるような気がしました。

VC++では実際にそうなります。一応確認のため複数のソースに分けて書いた関数で変数のポインタを表示させたところ、それぞれ異なるアドレスになっていました。

ちなみに、const int g_Test = 0;static const int g_Test = 0;でアセンブリソースを出力して比較しましたが、VC++では全く同じコードでした。

マクロと同等のものとして扱われるか?、

全く別物です。マクロは単なるテキストの置き換えですが、constグローバル変数は厳密に型を持った読み取り専用の変数として扱われます。

const付きのグローバル変数は、領域へのアクセス(ポインタ経由の参照など)を行わずに値を利用するだけなら、コンパイラーが使用箇所で数値に置き換えます。その場合、領域が確保されることもないので、結果的にはマクロで書いたのと同じような振る舞いに見えます。

ただし、単純な数値の置き換えができないような非組み込み型の場合は領域が確保されます。

投稿2016/05/20 13:32

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aoshanghai

2016/05/21 04:42

ご回答ありがとうございます。 大変参考になりました。 実施にアドレスを表示してみたら、異なるアドレスだったのですね。 また、マクロではないことと、コンパイラが場合によっては、 使用箇所を数値に置き換えてしまうので、領域が確保されない という点も大変参考なりました。 ご教示ありがとうございました。
guest

0

C++でもそうですが、言語の規格は、「どのように動く」かを定義するもので、「それをどのように実装すべきか」は、必要がなければ規定していません。

で、「const intが内部結合」ということは、「この変数は当該ファイル外からは使われ得ない」ということになります。

const volatileで最適化が阻止されているとか、ポインタを取るので実体の伴った変数として必要ということでなければ、この変数の代わりに直接値を書いても何も問題ありません。つまり、ファイル内を一通り見て最適化するとまずい使い方がなければ、定数として畳み込んでしまっても動作は全く同じです。変数として領域を確保するまでもありません。

投稿2016/05/20 13:10

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aoshanghai

2016/05/20 13:19

ご回答ありがとうございます。 大変参考になりました。 ということは、コンパイラによっては、const変数の使われ方次第で、 変数として領域を確保せずに、処理してしまう可能性がある ということですよね。 了解致しました。 ありがとうございました。
maisumakun

2016/05/20 13:39 編集

一般的なC言語のコンパイラの場合、外部結合するものは除いて、コンパイル後のオブジェクトコードはレジスタとメモリを直接扱うものです。つまり、(デバッグ情報で紐付けなければ)「変数名」という概念は雲散霧消しています。同じレジスタやメモリを、C言語では複数の変数だったものに流用しても、「ソースコードのとおりに動作するなら」一向に構いません。
episteme

2016/05/20 13:35

ってことは extern const int foo; はありえないと。 # それにしちゃ大抵の処理系でコンパイル・エラーにはならんのよね ^^;
maisumakun

2016/05/20 13:39

extern constとしたときはきちんと外部結合になる、とのことです。
episteme

2016/05/20 13:45

とはいえ リンク時にコケますよね? 内部結合なら複数のファイルで異なる値で const int foo = ほげほげ; できちゃうだから。
maisumakun

2016/05/21 03:29 編集

extern constを使う場合は、ふつうの変数同様にヘッダでは「extern const int foo;」として、1つのソースでこのヘッダを入れたうえでソースで「const int foo = 5;」とするのが正式のようです。
aoshanghai

2016/05/21 04:44

ご教示ありがとうございます。 コメントを拝見しながら考ええいたのですが、 私が変数の領域が確保されるかどうかと書きましたが、 メモリが確保されるかどうかと書いた方がより 正確だったのかもしれない、と思いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問