• ベストアンサー

volatile修飾について

組み込み系等でよく用いられる、volatile修飾子について質問させてください。 たまに、"volatile const int aaa" などと宣言された変数を見かけることがあります。 volatileやconstの意味はわかっているつもりですが、"const int aaa"ではなく、"volatile const int aaa"と宣言しなくてならないケースというのは、どういった場合があるのでしょうか? 具体的なコードで例を示していただけると助かります。 以上、よろしくお願いします。

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

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

> 私のつたない認識では、const宣言された変数はROMにマッピングされるものと思っております。 const修飾されたオブジェクトがROMに配置されるのは、非volatileの場合だけです。volatile修飾された場合は、const修飾子が付いていても初期化子も省略できます。これは組み込みであろうがなかろうが同じことです(コンパイラの不具合や非標準処理系の場合は知りません)。 > どんな要因でもaaaが変更されることはなく、つまりvolatileをつける意味がないように思えるのです。 先に書いたように、volatileが付いていれば原則としてRAMに配置されませんし、制御レジスタやI/Oポートの場合はリンカやアセンブラで指定したり、(*(const volatile unsigned char*)0x123456)のように定義したマクロなどを使うでしょうから、十分意味あることです。 仮にaaaがROMに配置された場合でも、バンク切り替えやフラッシュメモリの書き換えで値が変化する可能性はいくらでも考えられますね。

kappa_
質問者

お礼

>const修飾されたオブジェクトがROMに配置されるのは、非volatileの場合だけです 知りませんでした。 大変勉強になりました。ありがとうございます

その他の回答 (4)

  • rigidbody
  • ベストアンサー率60% (20/33)
回答No.5

>"volatile aaa"でいいような気がして ん?論点が摩り替わってしまっていますよ。命題は「volatileが必要か否か」ですよね?が、返信内容は「const intが必要か否か」になってしまっています。これではどちらを知りたいのか分かりません。 私が言いたい結論は、 「命題のvolatileコードを書いた人の意図は、"変数aaaに最適化操作を施さない絶対の安全性を保証したかった"のでは?」 という事です。 >constで宣言された変数はROM上にマッピングされる いいえ、volatile無しの変数なら必ず割り当てられる保証はありません。 前回お話した通りコンパイル時、前段処理が「const変数が何処にも使われた形跡が無い」と判断したら、後段処理(オプティマイザ)が「じゃあ削除しちゃえ!」とするような環境もあるからです。無い物をROMに割り当てる事はありませんから。 コンパイラの目には使われた形跡が無くとも、実は使っている場合もある訳です。間接的な参照の仕方をするコーディングも行えるからです(既述)。こういう時は、最適化段で勝手な真似をして欲しくない訳です。

kappa_
質問者

お礼

大変参考になりました。 理解できました。ありがとうございました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

#3です。 一箇所下記間違いました。 > volatileが付いていれば原則としてRAMに配置されませんし ×RAMに配置されません ○ROMに配置されません

  • rigidbody
  • ベストアンサー率60% (20/33)
回答No.2

>どういった場合があるのでしょうか? オプティマイザによる削除を避ける為ではないでしょうか。 一見 aaaを参照するコードが見当たらないようなソースがあったとします。 それをコンパイルすると、オプティマイザによってはaaaを削除される場合があります。が、valatile指定によりそれを避けようという意図ではないでしょうか。 一見、aaaを使わないように見えても、実際には即値アドレッシングによるポートアクセス等で、aaaを使う場合があります。が、コンパイラはそれを見抜く事ができない訳です。 こういう希な状況下においてvolatileを使ったのではないか、と推測しました。

kappa_
質問者

お礼

回答ありがとうございます。 私のうすい知識では、おっしゃているような状況では、"volatile aaa"でいいような気がしてしまいます。 組み込みでは、constで宣言された変数はROM上にマッピングされるため、値がどういう状況下でも変わらないと思っています。 間違ってますでしょうか?

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.1

早い話が入力ポートのようなものがconst volatile修飾されます。他には受信バッファなどもそうかと思います。 要するに、Cの文脈で値を変更することはできないけれども、別の要因で、読み込むたびに値が変化する可能性があるようなオブジェクトに対して指定します。

kappa_
質問者

お礼

早速の回答ありがとうございます。 私のつたない認識では、const宣言された変数はROMにマッピングされるものと思っております。 どんな要因でもaaaが変更されることはなく、つまりvolatileをつける意味がないように思えるのです。

関連するQ&A

  • volatileについて

    volatileの意味は分かってるつもりではいるのですが、どういったとき使うのかいまいちわかりません。何かソースの例かURLをよろしくお願いします。

  • const int i ? int const i ?

    お世話になります 初歩的な事ですがよろしくお願い致します const 修飾子って変数型の前につけるの?後につけるの? //---------------------------------------------------- const int iTest1[] = { 0x0000, 0x0000 }; const int iTest2[] = { 0xFFFF, 0xFFFF }; const int* const piTest[] = { iTest1, iTest2 }; //---------------------------------------------------- const int 型のポインタ配列をロム領域に確保したい場合は変数の後にconst修飾子をつけると思います const const int* piTest[] = { iTest1, iTest2 }; これだとエラーとなるはずです。。。 そこで、疑問に思ったのが、私の書式だと、const intとconst修飾子は前に着けるのが普通だと思ってました //----------------------------------------------------   const int i = 0;   int const i = 0; //---------------------------------------------------- でも、どちらでもコンパイルは通ると思います 配置領域を確認した所、どちらもROMに確保されてました 一般的にどちらが正解なのでしょうか? const const int* piTest[] = { iTest1, iTest2 }; が、エラーになるという事は、int const i が正解なのでしょうか? 教授よろしくお願い致します ちなみに、組み込み系に特化した話になっています windows系とかだとconst宣言は何処にいくんですかね・・・ ヒープじゃない予備領域とかあるんですかね・・・

  • 関数内でconst修飾子を使用した場合の配置

    お世話になります 関数内でconst修飾子を付加した領域を宣言します。 その領域は何処に取られるのでしょうか? RAM?ROM?スタック? コンパイル環境により異なるのでしょうか? void Test(void) { const int i_dat = 0;   ・・・・・・ } よろしくおねがいいたします。

  • volatile変数とROM領域について

    volatile変数というのは「揮発性変数」という意味です。 「電源を切るとデータが消える」要するに「RAM」であると 考えられます。 しかし、実際、「volatile」が使われるのは、もっぱら 組み込み業界であり、EEPROMアドレス領域変数変数につける 指定子だったりします。 この矛盾について説明いただけないでしょうか。

  • Java の配列の中身は volatile ですか?

    たとえば(無理やりな例ですが)、クラスが private final boolean isReady[] = {false, false}; public void setIsReady(int index, boolean isReady) {  this.isReady[index] = isReady; } public void doTask(int index) throws Exception {  while (! isReady[index] ) {   Thread.sleep(1000);  }  doSomething(); } のようなメンバとメソッドを持っていて、setIsReady() と doTask() がそれぞれ別のスレッドから呼ばれるような場合、doTask() の中の while ループはちゃんと抜け出す事が保証されますか? (もちろん isReady[index] を true にセットするとして。) isReady が配列ではなければ private volatile boolean isReady = false; としておけば安心できるのですが、配列の中身を明示的に volatile に宣言 出来ないようなので。(出来るのならばやり方を教えてください。)

  • switch文caseについて

    switchのcaseについてですが、数字を直接記述せずに、const変数に値を代入して使用出来ますか? 例) const int A = 1; const int B = 2; switch(suuti){ case A: 処理; break; case B: 処理; break; } コンパイルすると、「case 式は、整数型定数でなければなりません。」と出てきてしまうのですが、直接数値を記述しないといけないのでしょうか? よろしくお願いします。

  • 文字列のメンバ変数を外部変数のように扱いたい

    済みません。質問なのですが、 メンバ変数を外部変数のように扱うにはどうしたらよいのでしょうか? int型などの場合、 class test{ static const int a; }; const int test::a = 10; とすればよいですよね? これをcharの配列にして class test{ static char a[7][32]; }; char test::a[0] = "test"; とすると サイズが0の配列を割り当てまたは宣言しようとしました というコンパイルエラーがでてしまいます…。 多次元配列の場合はstatic変数としてもてないのでしょうか? char** として宣言してもどこでnewを行えばよいか解りません。 コンストラクタの中で行えば そこでstaticではなくなってしまいますし…。 後、できればstringクラスの配列で持ちたいのですが #include <string> class test{ static string test[7]; }; string test::test[0] = "aaa"; なんてことができますでしょうか? 質問内容が解りにくいかも知れませんが どうか教えてください。 宜しくお願いいたします。

  • static constメンバ変数(配列)の初期化について

    C++初心者です。 constメンバ変数の初期化について教えてください。 クラスの中に、static constメンバ変数(配列)を持ちたいのですが、 <コード1> class hoge { public : hoge(){}; virtual ~hoge(){}; static const int fuga[2] = {1, 2}; }; とすると、VC++ 2005では、 error C2059: 構文エラー : '{' error C2334: '{' の前に予期しないトークンがありました。関数の本体は無視されます というエラーが発生します。 何がいけないのでしょうか? また、下の様にするとOKでした。 <コード2> class hoge { public : hoge(){}; virtual ~hoge(){}; static const int fuga[2]; }; const int hoge::fuga[2] = {1,2}; こうすればコンパイルが通る事は分かったのですが、なぜこんな面倒な事をしないといけないのかが分かりません。 コード1では何がいけないのでしょうか? 以上、よろしくお願いします。

  • メンバ変数宣言時にfinal修飾子

    いつも御世話になっています。 final修飾子を使用する際で、メンバ変数宣言時で、 オブジェクト型変数にfinalをつけた際、値を変更できると思うのですが。 インターフェースで考えた時はどうなるのでしょうか? クラス型だと, final ClassA object1 = new ClassA(); classA.value = 10; //valueはint型 と記述されると思うのですが、 また、配列だと, final String[] hairetu = {"one","two"}; classA.strValue = hairetu; とするのがいいのでしょうか? 宜しくお願いします。

    • ベストアンサー
    • Java
  • 名詞の修飾のルールについて

    過去分子(形容詞?)が名詞を修飾する場合、 Scheduled maintenance Unsupplied hours  のように前から修飾している場合と All the parties involved Decision made のように後ろから修飾している場合がありますが この二つに意味や文法上のルールの違いがあるのでしょうか? 具体例がうまく見つけられず、質問の仕方も曖昧かもしれませんが どなたか分る方、教えて下さい。宜しくお願いします。

専門家に質問してみよう