web-dev-qa-db-ja.com

intをポインタにキャストする-なぜ最初にlongにキャストするのですか? (p =(void *)42のように;)

GLib のドキュメントには、型変換マクロに関する章があります。 int*voidポインタに変換することについての議論では、それは次のように述べています(強調は私のものです):

単純に、これを試すかもしれませんが、それは正しくありません。

gpointer p;
int i;
p = (void*) 42;
i = (int) p;

繰り返しますが、その例は正しくありません。コピーしないでください。 問題は、一部のシステムではこれを行う必要があることです:

gpointer p;
int i;
p = (void*) (long) 42;
i = (int) (long) p;

(出典:GLib 2.39.92のGLibリファレンスマニュアル、章 Type Conversion Macros )。

なぜlongへのキャストが必要なのですか?

intの必要な拡大は、ポインターへのキャストの一部として自動的に行われるべきではありませんか?

15
sleske

C99: 6.3.2.3の見積もりによると:

5整数は任意のポインタ型に変換できます。以前に指定された場合を除き、結果は実装定義であり、正しく整列されていない可能性があり、参照されたタイプのエンティティをポイントしていない可能性があり、トラップ表現である可能性があります。56)

6ポインタ型は整数型に変換できます。前述の場合を除き、結果は実装定義です。結果を整数型で表現できない場合の動作は未定義です。結果は、整数型の値の範囲内である必要はありません。

link のドキュメントによると、

ポインタのサイズは常に32ビット以上です(すべてのプラットフォームでGLibがサポートする予定です)。したがって、ポインタ値には少なくとも32ビットの整数値を格納できます。

そしてさらに longは少なくとも32ビットであることが保証されています

したがって、コード

gpointer p;
int i;
p = (void*) (long) 42;
i = (int) (long) p;

gLibで宣伝されているように、より安全で移植性が高く、32ビットまでの整数に対してのみ明確に定義されています。

10
askmish

これは、この変換が実装依存であるためだと思います。特定の実装ではポインタ型のサイズであるため、この目的にはuintptr_tを使用することをお勧めします。

2
DoctorMoisha