マンガでよめる痔のこと・薬のこと

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

このQ&Aに関連する最新のQ&A

A 回答 (5件)

> 私のつたない認識では、const宣言された変数はROMにマッピングされるものと思っております。



const修飾されたオブジェクトがROMに配置されるのは、非volatileの場合だけです。volatile修飾された場合は、const修飾子が付いていても初期化子も省略できます。これは組み込みであろうがなかろうが同じことです(コンパイラの不具合や非標準処理系の場合は知りません)。

> どんな要因でもaaaが変更されることはなく、つまりvolatileをつける意味がないように思えるのです。

先に書いたように、volatileが付いていれば原則としてRAMに配置されませんし、制御レジスタやI/Oポートの場合はリンカやアセンブラで指定したり、(*(const volatile unsigned char*)0x123456)のように定義したマクロなどを使うでしょうから、十分意味あることです。

仮にaaaがROMに配置された場合でも、バンク切り替えやフラッシュメモリの書き換えで値が変化する可能性はいくらでも考えられますね。
    • good
    • 0
この回答へのお礼

>const修飾されたオブジェクトがROMに配置されるのは、非volatileの場合だけです

知りませんでした。
大変勉強になりました。ありがとうございます

お礼日時:2005/10/05 15:59

>"volatile aaa"でいいような気がして


ん?論点が摩り替わってしまっていますよ。命題は「volatileが必要か否か」ですよね?が、返信内容は「const intが必要か否か」になってしまっています。これではどちらを知りたいのか分かりません。

私が言いたい結論は、
「命題のvolatileコードを書いた人の意図は、"変数aaaに最適化操作を施さない絶対の安全性を保証したかった"のでは?」
という事です。

>constで宣言された変数はROM上にマッピングされる
いいえ、volatile無しの変数なら必ず割り当てられる保証はありません。
前回お話した通りコンパイル時、前段処理が「const変数が何処にも使われた形跡が無い」と判断したら、後段処理(オプティマイザ)が「じゃあ削除しちゃえ!」とするような環境もあるからです。無い物をROMに割り当てる事はありませんから。

コンパイラの目には使われた形跡が無くとも、実は使っている場合もある訳です。間接的な参照の仕方をするコーディングも行えるからです(既述)。こういう時は、最適化段で勝手な真似をして欲しくない訳です。
    • good
    • 0
この回答へのお礼

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

お礼日時:2005/10/05 15:59

#3です。


一箇所下記間違いました。

> volatileが付いていれば原則としてRAMに配置されませんし

×RAMに配置されません
○ROMに配置されません
    • good
    • 0

>どういった場合があるのでしょうか?


オプティマイザによる削除を避ける為ではないでしょうか。

一見 aaaを参照するコードが見当たらないようなソースがあったとします。
それをコンパイルすると、オプティマイザによってはaaaを削除される場合があります。が、valatile指定によりそれを避けようという意図ではないでしょうか。

一見、aaaを使わないように見えても、実際には即値アドレッシングによるポートアクセス等で、aaaを使う場合があります。が、コンパイラはそれを見抜く事ができない訳です。

こういう希な状況下においてvolatileを使ったのではないか、と推測しました。
    • good
    • 0
この回答へのお礼

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

お礼日時:2005/10/05 14:37

早い話が入力ポートのようなものがconst volatile修飾されます。

他には受信バッファなどもそうかと思います。

要するに、Cの文脈で値を変更することはできないけれども、別の要因で、読み込むたびに値が変化する可能性があるようなオブジェクトに対して指定します。
    • good
    • 0
この回答へのお礼

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

お礼日時:2005/10/05 14:28

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qvolatile修飾子について

はじめまして。
現在C言語を学習しているのですが、現在使用している参考書には
volatile修飾子の説明がほとんどなく、どういった機能なのかが
わかりません。volatile修飾子とはどういうときに使用するものなので
しょうか?できれば、volatileの機能が確認できるような
簡単なサンプルがあればうれしいです。どうかご教授お願いします。

Aベストアンサー

パソコン上で動かすプログラムを書く人だとあまり使わないかもしれませんね.
ただ, #1の方もおっしゃる様に, ハードウェアに近い分野では必要になる場合もあります.

volatile修飾子がついた変数には最適化が働かなくなります.
たとえば, 次のようなコードがあるとします.

long counter;

printf("a\r\n");
for( counter = 0; counter < 100000; counter++ );
printf("b\r\n");
for( counter = 0; counter < 100000; counter++ );
printf("c\r\n");

上記コードでは, for文で無意味なループを回して無駄時間を作っているつもりです.
a, b, cの間に少しタイムラグができるはずです.
(実際にはとわからないと思いますが)

ただ, 前のコードは実行速度の点でコンパイラから見ても明らかに無駄です.
したがって, コンパイラは次の様な具合にコードを最適化してしまう場合があります. (処理系依存です)

long counter;

printf("a\r\n");
printf("b\r\n");
printf("c\r\n");
counter = 100000;

処理が終わった時点では最初のコードと最適化後のコードは同じ事ですが,
無駄処理で時間稼ぎをしていた部分が無くなってしまいました.
処理速度向上といえばそうですが, これでは困ります.
(なお, counter変数を後で使わない場合は変数の存在自体が無かった事にされたりもします)

そんな時に, counter変数の宣言時にvolatileをつけて
volatile int counter;
といった具合にすると, counter変数に関連する処理は最適化の対象外となるため,
プログラマが書いたとおりに動作するようになります.

なお, 先のコードは説明の為のコードであまり意味がありませんが,
実際だと「メモリマップドI/O」(メモリの特定のところにデータを書き込むと
ハードウェア的に何らかの動作が起こる仕組み)
などをいじる時はvolatile修飾子が必須となります.

パソコン上で動かすプログラムを書く人だとあまり使わないかもしれませんね.
ただ, #1の方もおっしゃる様に, ハードウェアに近い分野では必要になる場合もあります.

volatile修飾子がついた変数には最適化が働かなくなります.
たとえば, 次のようなコードがあるとします.

long counter;

printf("a\r\n");
for( counter = 0; counter < 100000; counter++ );
printf("b\r\n");
for( counter = 0; counter < 100000; counter++ );
printf("c\r\n");

上記コードでは, for文で無意味なループを回し...続きを読む

QAD変換のLSB(量子化単位)の求め方。

AD変換のLSB(量子化単位)を求める式について質問があります。
8ビット分解能の場合、LSBの計算式は以下の式になるようですが、
 LSB = Vref/256 (※Vref:リファレンス電圧)

なぜ"256"で割るのか分かりません・・
次のように"255"ではないんでしょうか。
 LSB = Vref/255

例えば 8ビット分解能、Vref=255Vの場合、次のようなAD変換結果に
なると思います。
 0V = 00000000b
 1V = 00000001b
 2V = 00000010b
   :
 254V = 11111110b
 255V = 11111111b

この場合、LSBは1Vではないでしょうか。
となると、
 LSB = Vref/x
の計算式より
 x = Vref/LSB = 255V/1 = 255

となり "255"で割ることが正しいのではないんでしょうか??

Aベストアンサー

LSBは最下位ビットによる変位幅なので、質問者さんの考え方であっていると思います。
私はそのように教わりました。
失礼ですが、参考文献に誤りがあるのではないでしょうか。

No1の方は256を主張していますが、カードの例えで1LSB=1=(3-0)/(2^2-1)から分解能nビットのAD変換について範囲を(2^n-1)で割るのが正しいことを証明していますね。

Q「#undef」と「#define」の使い方について

代記のとおりですが、

#undef HENSU
#define HENSU 16MAX

という定義をした場合は、#undefで一旦定義を無効にして、
#defineで再定義されるという認識でよろしいでしょうか?

ご存知の方教えてくださいお願いします。

Aベストアンサー

よろしいです。

#ifdef HENSU
#undef HENSU
#endif
#define HENSU ...

の方がより安全かも。

Q組み込みソフト。ROM領域にデータ

C でデータに const 属性をつけて、初期値を設定して定義すると、初期値は ROMにテーブルが作られますがデータ自体は RAM領域に配置されます。
RAMの節約のため、ROM領域にデータを配置する方法はないのでしょうか。

Aベストアンサー

#pragma section data = ".rodata"
//ROM配置したいデータ

#pragma section data = default

等のコンパイラやアセンブラのコマンドを使ってデータが配置される領域をROM領域に設定してください。
必要に応じてリンカディレクティブファイルまたはリンクディレクティブなどと呼ばれるファイルを編集してROM領域を示すセクションを追加してください。

注)他の回答にあるようにあなたの使用している環境に合わせてください。

QC言語のポインタに直接アドレスを割り振りしたい

C言語のポインタに直接アドレスを割り振りしたいのですが、どうしたら良いのでしょうか?

Aベストアンサー

直接アドレスを割り振りたい、というのは
int* pnValue;
pnValue = (int*)0x12345678
ということでしょうか?このようにすればポインタにアドレスを代入することはできるかと思います。

Qラッパーって何なんでしょう・・・?

C++を勉強し始めたのですが、何とも難しい言葉が多くて、書いてあることが本当に理解できません。
ラッパーって?
ハンドルって??
と、次から次へと理解不能な言葉が・・・
読んでいるのは、C++Builderの開発者ガイドと、プログラミング言語C++の本です。
具体的なイメージが浮かばず、概念自体もピンときません。
わかりやすい本などあったら教えてください。
また、とりあえずラッパーとハンドルがどうしても気になるので、この2つの意味教えてください!!
よろしくお願いします。

Aベストアンサー

ラッパーは、wrapper で包み込むものの意味です。
wrap ラップはサランラップのラップですね。
wrappingラッピングといえば、プレゼントを包むやつですね。

つまり、たとえばある関数を使いたいと思ったとします。
しかし、その関数を呼び出すには、いろんな手続きをしないといけない、また呼ぶときに渡す引数をたくさん設定しなければならないなど、使用するのが面倒な場合があります。
これはその関数が汎用的に使えるように、動作に自由度を持たせていると、面倒になる傾向にあります。

そんな時、引数なし、又は簡単な引数で呼び出せるような関数を作ってあげれば楽になります。
この場合は、ある程度用途が決まっているので、その関数を呼び出すときの手続きを省略してくれるような関数ですね。
それがラッパーというわけです。

あと良くあるのが、C言語で書かれたライブラリなどをC++の機能を使って使いたいときに、ラッパーを作ったりします。
この場合は逆に機能を追加して使いやすくするイメージですね。

ハンドル(handle)はつまり何かを操作するときのハンドル(車のハンドルと同じ)です。

この概念は良く使われます。
たとえば、ハードディスクにはファイルがたくさん入っています。
その中のファイルを開いて何か処理しようとします。するとディスクアクセスの処理をしなければなりませんが、それを自分で書くのは大変なので、ライブラリを使います。
ライブラリでは、
・指定されたファイルを開く関数
・指定されたファイルの中身を読み出す関数
・指定されたファイルに指定の文字を書き出す関数
などなどたくさん用意します。

ここで一つ問題が生じます。もし複数のファイルを同時に処理したい場合どうやったらよいでしょう。
いちいちファイル名で指定する方法も考えられますが、ファイルを開くときに一つのハンドルという名前の変数を用意し、その変数の中にどのファイルであるという情報、そのファイルのサイズ、そのほか必要な情報を一つにまとめておくと、ファイルを操作するときにはその変数を引数として渡すだけで、ファイルがどれであるのかという指示が簡単に出来ます。

いまファイルハンドルを例にあげましたが、他にもWindowsではたくさんのWindowを開きますので、それら一つ一つにもハンドルが用意されています。

基本的に、

・同種のものが複数ある
・上記に対して操作する関数が複数ある

という条件を満たすようなものに対しては、ハンドルという概念でコントロールすることがよくあります。

ラッパーは、wrapper で包み込むものの意味です。
wrap ラップはサランラップのラップですね。
wrappingラッピングといえば、プレゼントを包むやつですね。

つまり、たとえばある関数を使いたいと思ったとします。
しかし、その関数を呼び出すには、いろんな手続きをしないといけない、また呼ぶときに渡す引数をたくさん設定しなければならないなど、使用するのが面倒な場合があります。
これはその関数が汎用的に使えるように、動作に自由度を持たせていると、面倒になる傾向にあります。

そんな時、引...続きを読む

Qint型からchar型への変換

タイトル通り、int型からchar型への変換の仕方がわかりません!><
どうしたらいいのでしょうか?

Aベストアンサー

#include <stdio.h>


char buf[5];
int no;

no = 10;
sprintf(buf, "%d", no);

QC言語のグローバル変数の初期化について

C言語において
int a = 1; // 動的グローバル変数
static int b = 2; //静的グローバル変数

funcA(){
int c = 3; // 動的ローカル変数
static int d = 4; //静的グローバル変数



}
上記のように各種変数を初期化したとします。
"c"のような動的ローカル変数であれば、funcA()が呼ばれたときに毎回初期化されますよね?

では
・"d"のような静的ローカル変数は、初めてfuncA()が呼ばれたときに初期化されるのですか?
・"a","b"のyほうなグローバル変数は、どのタイミングで初期化されるのですか?

以上2点について伺いたいと思います。

ちなみに、組み込み機器むけのソフトウェアを想定しています。

Aベストアンサー

No.11 = Interest です。

> コンパイル時に"a","b","d"の領域が.dataセクションに確保される。

コンパイル時ではなく、リンク時です。リンク前は、これらのデータがどこに配置されるかまだ決まっていません。

> コンパイル時にスタートアップルーチンが自動生成され(?)

これ、違います。
スタートアップルーチンが自動生成されるとすれば、統合開発環境などを使ってプロジェクトを生成したときです。統合開発環境を使ってなければ、スタートアップルーチンを手で書くこともあります。(どこかからコピーしてくるほうが楽ですが。)コンパイル時に自動生成されるものではありません。


> main関数実行前に、

これは間違いではありませんが、注意が必要です。
CPUに電源が供給されて一番最初に走り始めるプログラムがスタートアップルーチンです。スタートアップルーチンが「いわゆるmain関数」を呼び出します。すでにご存じと思いますが、組み込みの世界では必ずしも main関数があるわけではないので、「main関数実行前に」という考えかたは適切ではありません。

> スタートアップルーチンが変数をROM→RAMへとコピーする際に、.dataセクションの変数を初期化する。(.bssセクションは0初期化する)

「変数をROM→RAMへとコピーする」ことと、「.dataセクションの変数を初期化する」ことは同じことです。言い換えれば「.dataセクションの変数を初期化するために、ROMに格納されている初期値をRAMへとコピーする」ってこと。

No.11 = Interest です。

> コンパイル時に"a","b","d"の領域が.dataセクションに確保される。

コンパイル時ではなく、リンク時です。リンク前は、これらのデータがどこに配置されるかまだ決まっていません。

> コンパイル時にスタートアップルーチンが自動生成され(?)

これ、違います。
スタートアップルーチンが自動生成されるとすれば、統合開発環境などを使ってプロジェクトを生成したときです。統合開発環境を使ってなければ、スタートアップルーチンを手で書くこともあります。(どこかから...続きを読む

QLNK2019: 未解決の外部シンボルのエラーが出る

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自キャラのデータ
Point2D g_jikipos = {40, 400};//自キャラの座標

//画像ハンドル
int g_jikiimage[11];

//色々なファイルの読み込み
int LoadFiles(){
//画像ファイル読み込み
if(LoadDivGraph("media\\player01.bmp",
11,11,1,64,64,g_jikiimage) == -1) return -1;

return 1;
}


 mymain.h
//他から呼び出させるMyMainの関数
void MyMain();
int LoadFiles();


 myhelper.h(サンプルなので打ちミスはない)
#include "DxLib.h"
#include <limits.h>
#include <math.h>

//構造体宣言
//座標またはベクトルを記録する構造体
struct Vector{
float x,y;
};
typedef Vector Point2D;
//線を記録する構造体
struct Line2D{
Point2D startpos, endpos;
float katamuki;//傾きをラジアン値で記録
Vector speed;//移動している場合は速度をセット
};
//球体を記録する構造体
struct Ball2D{
Point2D position;
float hankei;//半径
};
//四角形を記録する構造体
struct Rect2D{
Point2D lefttop;
Point2D rightbottom;
float width;
float height;
};


//ライブラリ関数
Point2D PosInView(Point2D in);
int XInView(float inx);
int YInView(float iny);
void ScrollToLeft(float jikiposx);
void ScrollToRight(float jikiposx);
void ScrollToUp(float jikiposy);
void ScrollToDown(float jikiposy);
void DrawLineInView(float x1, float y1, float x2, float y2, int Color, int Thickness);
void DrawCircleInView(float x, float y, float r, int Color, int FillFlag);
void DrawAnimation(float x, float y, double ExtRate, double Angle,int TurnFlag,
int *imgarray, int allframe, float fps);
//ベクトル関数
Vector CreateVector(Vector in, float veclen);
Vector AddVector(Vector v1, Vector v2);
Vector SubVector(Vector v1, Vector v2);
Vector AddVectorInFrameTime(Vector pos, Vector speed);
Vector AddVectorInFrameTime2(Vector pos, Vector speed, Vector accel);
Vector Normalize(Vector in);
Vector RotateVector(Vector in, float radian);
float VectorLengthSquare(Vector in);
float DotProduct(Vector v1, Vector v2);
float CrossProduct(Vector v1, Vector v2);
void SetLine2DKatamuki(Line2D *in);
void DrawLine2D(Line2D in, int Color, int Thickness);
void DrawBall2D(Ball2D in, int Color, int Fill);
//当たり判定関数
bool HitTestLineAndBall(Line2D linein, Ball2D ballin);
bool IsPointAtLineFace(Line2D linein, Point2D ptin);
bool HitTestLineAndLine(Line2D line1, Line2D line2);
bool HitTestBallAndBall(Ball2D a, Ball2D b);
bool HitTestPointAndBox(Rect2D rect, Point2D pt);
//タイマー関数
void SetSimpleTimer(int idx, int time);
int GetPassedTime(int idx);


//グローバル変数
extern float g_frametime;
extern Rect2D g_framerect;//画面領域(当たり判定)
extern Point2D g_current_field_pos;//現在の左上座標
extern Rect2D g_stagesize;//ステージサイズ

//定数宣言
const float ZEROVALUE = 1e-10f;
const float PIE = 3.1415926f;
const int SCROLL_LIMIT = 200;
----------------------------------------------------------------
 エラー内容
1>myhelper.obj : error LNK2019: 未解決の外部シンボル "void __cdecl MyMain(void)" (?MyMain@@YAXXZ) が関数 _WinMain@16 で参照されました
1>C:\Documents and Settings\Owner\My Documents\Visual Studio 2008\Projects\my\Debug\my.exe : fatal error LNK1120: 外部参照 1 が未解決です
1>my - エラー 2、警告 0
ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ
----------------------------------------------------------------
画像を貼り付けときます
(見えにくい場合→http://www.dotup.org/uploda/www.dotup.org154142.jpg.html)
初心者なのでわかりやすくお願いします

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
----------------------------------------------------------------
新しいプリジェクト→Win32 コンソール アプリケーション(ソリューションのディレクトリを作成 チェック外す)→Windows アプリケーション(空のプロジェクト チェック外す)
----------------------------------------------------------------
 プログラム

 mymain.cpp
#include "myhelper.h"
#include "mymain.h"

//自...続きを読む

Aベストアンサー

ファイル構成から推測するに
mymain.cpp というファイルに
void MyMain(void) {
// ここに処理を書く
}
という関数が必要なようです。

QEXCEL VBA で現在開いているブックのファイル名を取得する方法

EXCEL2003 VBAで業務を簡素化するために、現在開いているブックのファイル名を取得する方法が分かりません。
作業手順をマクロを使って処理していますが、オリジナルのワークブックをファイル名を変えて保存し、以後、このワークブックを読み込んで使用しています。
このときのVBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり、以後の業務に使用できません。
常にファイル名を取得出来るVBAをどなたか、教えて下さい。

Aベストアンサー

>現在開いているブックのファイル名
 ちょっと曖昧な表現かなぁという気もいたしますが、VBAが書いてあるブックのブック名は
ThisWorkbook.Name
で、現在 "アクティブにして" 操作対象になっているブックの名前は
ActiveWorkbook.Name
ですね。

 しかし、
>VBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり
というような文脈からすると、
ThisWorkbook.Name
の方ですかね。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング