6

皆さん、

この(忌まわしい)コードを考えてみましょう。

volatile unsigned long a[1];  
unsigned long T; 

void main(void) 
{    
    a[0] = 0x6675636b;   /* first access of a */
    T = *a; 
    *(((char *)a) + 3) = 0x64; /* second access of a */
    T = *a;
}

...質問:((char *)a)揮発性ですか、それとも不揮発性ですか?

これはより大きな疑問を投げかけます:の2つのアクセスの間に依存関係があるべきですか?つまり、人間の常識ではあると言われていますが、C99標準では、揮発性のものは不揮発性のものをエイリアスしないとされています。したがって、((char *)a)が不揮発性である場合、2つのアクセスはエイリアスせず、依存。

より正確には、C99 6.7.3(パラ5)は次のようになります。

「不揮発性修飾型の左辺値を使用して揮発性修飾型で定義されたオブジェクトを参照しようとした場合、動作は未定義です。」

では、型キャストするときa、揮発性修飾子は適用されますか?

4

2 に答える 2

1

疑わしい場合は、いくつかのコードを実行してください:)私はいくつかの同様の(少し嫌悪感が少ない)テストコードを作成しました(msvs2k10のwin32C ++アプリ)

int _tmain(int argc, _TCHAR* argv[]) {
    int a = 0;
    volatile int b = 0;

    a = 1; //breakpoint 1
    b = 2; //breakpoint 2
    *(int *) &b  = 0; //breakpoint 3
    *(volatile int *) &b  = 0; //breakpoint 4

    return 0;
}

リリース用にコンパイルすると、2と4でブレークポイントを設定できますが、1と3ではブレークポイントを設定できません。

私の結論は、型キャストが動作を決定し、1と3が最適化されたということです。直感はこれをサポートします-そうでなければ、コンパイラは、識別子のタイプ(より簡単でより直感的)に関連付けるのではなく、揮発性としてリストされたメモリのすべての場所のあるタイプのリストを保持し、すべてのアクセス(ハード、醜い)をチェックする必要があります。

また、これはコンパイラ固有であり(コンパイラ内でもフラグ固有である可能性があります)、この動作に依存する前に任意のプラットフォームでテストすることになると思います。

実際にそれをスクラッチします、私は単にこの振る舞いに依存しないようにします:)

また、あなたが特に配列について質問していたことは知っていますが、それが違いを生むとは思えません。配列の同様のテストコードを簡単に作成できます。

于 2012-11-07T17:55:41.433 に答える
0

あなたが言ったように、その「未定義」。つまり、悪魔があなたの鼻から出てくる可能性があります。可能な限り「定義された」動作に固執してください。指定者は、値を最適化しないvolatileようにコンパイラーに要求します。これは、最適化メカニズムが異なるために変更された場合に問題を引き起こす可能性がある「重要」で重要な値だからです。しかし、それができることのすべてです。

于 2012-11-02T16:42:33.280 に答える