17

volatile 型へのポインターを cout しようとすると、通常は cout が文字列を出力すると予想される volatile char ポインターであっても、代わりに単に '1' を取得します (ポインターが null でないと仮定します)。出力ストリーム operator<< は揮発性ポインターに特化したテンプレートだと思いますが、私の質問はなぜですか? この動作の動機となるユースケースは何ですか?

コード例:

#include <iostream>
#include <cstring>

int main()
{
    char x[500];
    std::strcpy(x, "Hello world");

    int y;
    int *z = &y;

    std::cout << x << std::endl;
    std::cout << (char volatile*)x << std::endl;

    std::cout << z << std::endl;
    std::cout << (int volatile*)z << std::endl;

    return 0;
}

出力:

Hello world
1
0x8046b6c
1
4

4 に答える 4

28

ostream::operator<<とりわけ、次のオーバーロードがあります。

ostream& operator<< (bool val );
ostream& operator<< (const void* val );

volatile ポインターを渡す場合、明示的なキャストなしでは volatile ポインターを非 volatile に変換できないため、2 番目のオーバーロードは適用できません。ただし、任意のポインターを bool に変換できるため、最初のオーバーロードが選択され、表示される結果は 1 または 0 になります。

したがって、これの本当の理由は、標準化委員会に代わって意図的に決定したことではなく、単純に、標準が揮発性ポインターを取るオーバーロードを指定していないためです。

于 2010-03-23T16:39:31.830 に答える
5

その理由は、volatile ポインターを暗黙的に void * に変換できないためだと思います。これは標準の付録 C にあり、その根拠は型の安全性です。

変更: 非 const および非 volatile オブジェクトへのポインターのみが暗黙的に void* に変換される可能性があります。 根拠: これにより、型の安全性が向上します。

したがって、(16 進数で出力される) void * への変換の代わりに、bool への「既定の」変換が行われます。

于 2010-03-23T16:42:55.000 に答える
2

答えではありません

これは、質問と回答の文言の問題です。この問題は、volatile オブジェクトへのポインターを volatileポインターではなく void ポインターに変換できないために発生します。

かなり重要な違いは、どのメモリ要素が揮発性であるかということです。問題では、ポインターは揮発性ではなく (キャッシュすることができ、変更されたときにメモリにフラッシュする必要はありません)、ポイントされたメモリです。

int volatile * p = f();
p++;      // this does not affect the perceived state of the c++ memory model
++p;
*p = 5;   // this changes the perceived state

これが重要な理由は、メモリへの揮発性ポインターでは、ポインター自体が特別な扱いを受けるためです。

void foo( int * );

int * volatile p = f();  // 1
foo(p);                  // 2
int volatile * q = f();
//foo(q);    // error, cannot convert pointer to volatile to pointer to non-volatile
*q = 5;                  // 3
q = 0;                   // 4

上記のコードでは、1 と 2 でマークされた操作によって、メモリまで到達します。[1] の割り当ては、メモリにダンプする必要があります。の値がpレジスタにある場合でも、[2] でメモリからロードされます。[3] とマークされた操作は、qそれが指す値を変更し、volatileメイン メモリまでずっと作成しますが、操作 [4] は、volatileそれ自体ではないポインターにのみ影響を与えるため、C++ メモリ モデルの一部ではありません。認識可能な状態であり、レジスターで実行できます (コンパイラーは、最適化することはできませんが、最適化qしてレジスターで操作を実行できることに注意してくださいp

于 2010-03-23T17:25:52.780 に答える
1

問題は、揮発性型へのポインターの明示的なオーバーロードではなく、揮発性型へのポインターのオーバーロードの欠如だと思います。コンパイラは、ポインターから volatile 修飾子を暗黙的に削除できないため、使用可能なオーバーロードをチェックし、operator<< の bool バージョンを選択して、volatile へのポインターを bool に変換します。

于 2010-03-23T16:46:14.777 に答える