addr
は関数のパラメータであり、read_value
は関数のローカル変数です。どちらもint型です。ポインタの変数への代入
次に何をん:
read_value = (* (int *) (addr))
はどういう意味ですか?
addr
は関数のパラメータであり、read_value
は関数のローカル変数です。どちらもint型です。ポインタの変数への代入
次に何をん:
read_value = (* (int *) (addr))
はどういう意味ですか?
addr
をintへのポインタにキャストし、逆参照してread_value
に入れます。
addr
が実際にはint
の場合、それは未定義の動作だと思います。
(int *) (addr)
は、addr
の数値をint *
ポインタにキャストします。特別な注意が払われない限り、addr
の任意の値がint
のアライメント要件に違反する可能性があるため、この操作は安全ではありません。一般に、addr
の値がint
のサイズの倍数ではない場合、それは最終的にSIGBUS
信号をもたらすことがある不整合読み取りにつながる可能性があります。
最後に、アスタリスクは、そのアドレスにあるint
値(逆参照と呼ばれます)を取り出してread_value
に保存します。アドレスが十分に整列されていない場合、位置合わせ不良リードが発生するのはこの時点である。参照が制限されたり保護されたりすると、逆参照によってセグメント違反が発生する可能性があります。
ことがint *
にキャストの間、より安全性を与えるので、私は実際には、むしろint
よりも、タイプuintptr_t
であることがaddr
を宣言します。 uintptr_t
は、ポインタのサイズと表現に対応する必要がありますが、int
タイプは意味的にポインタと無関係です。
ここに追加するだけで、このプラクティスは「型打ち」として知られています。そして言及したように、それは危険です。アライメントが分からない場合は、代わりに 'memcpy()'を使って 'int'値を読み込みます。 – FatalError
は、次の例を見てみましょう:
int read_value = 0;
int address = 0x1234;
read_value = *(int *) address;
これは同等です:
read_value = *(int *) 0x1234;
これはアドレス0x1234
とread_value
オブジェクトに格納しでint
を読み込みます。 int
値0x1234
を最初にint
へのポインタに変換してから、ポインターを逆参照してint
の値にアクセスすることによって行われます。
変換(int *) 0x1234
は実装定義です。
(C99、6.3.2.3p5)「整数が先に指定された場合を除き、結果は実装定義され、正しく整列されないことがあります。任意のポインタ型に変換することができる、の実体を指していない可能性があります参照された型であり、トラップ表現である可能性があります。
そして、ポインタが間違っている場合、または正しい位置合わせがない場合、ポインタの逆参照は未定義の動作です。無効なポインタを使用すると、未定義の動作になります。無効なポインタは、nullではないが、適切なオブジェクトまたは関数を指していないポインタです。
キャストの結果が表現できない値になるのは、未定義の動作のみです。 (C11 6.3.2.3参照)。 – Lundin