web-dev-qa-db-ja.com

void *の代わりにintptr_tを使用していますか?

intptr_tの代わりにvoid*を(ポインターと整数値を保持するための)汎用ストレージとして使用することは良い考えですか? (ここに示されています: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html

私がすでに読んだことについて:

  • int-> void*-> int往復は元の値を保持することが保証されていません。 int-> intptr_t-> intでできると思います
  • void*intptr_tの両方のポインター演算にはキャストが必要なので、ここでは利点がありません。
  • void*は、ポインタを格納するときの明示的なキャストが少ないことを意味し、intptr_tは、整数値を格納するときのキャストが少ないことを意味します
  • intptr_tにはC99が必要

他に何を考慮すべきですか?

24
Gepard

_intptr_t_の代わりに_void*_を(ポインタと整数値を保持する)汎用ストレージとして使用することは良い考えですか?

番号。

_intptr_t_の存在は保証されていません。まず、お気づきのように、C99で導入されました。次に、実装は、情報を失うことなく変換されたポインタ値を保持するのに十分な大きさの整数型である必要はありません。

intを_intptr_t_に変換して元に戻すと、unlikelyで情報が失われますが、実際に_intptr_t_になる保証はありませんintより広いです。

ポインタ値を格納する場合は、ポインタオブジェクトに格納します。それが、ポインタオブジェクトの目的です。

オブジェクトまたは不完全な型へのポインターは_void*_に変換でき、情報を失うことなく再び元に戻すことができます。関数へのポインターについてはそのような保証はありませんが、関数へのポインター型は他の関数へのポインター型に変換でき、情報を失うことなく元に戻すことができます。 (私はC標準を参照しています。POSIXはいくつかの追加保証を提供すると思います。)

整数値またはポインタ値を同じオブジェクトに格納する場合、最初に行うべきことは、設計を再考することです。既に実行していて、本当にこれを実行する必要があると判断した場合は、共用体を使用することを検討してください(最後に保存した値の種類を注意深く追跡します)。

_void*_引数を使用して任意のデータを渡すことができるAPIがあります。たとえば、POSIX pthread_create() 関数を参照してください。これは、整数値を_void*_にキャストすることで悪用される可能性がありますが、整数オブジェクトのaddressを渡す方が安全です。

30
Keith Thompson

いいえ、特定の型がポインタと整数の両方を格納するための合理的な方法であるとは保証できません。また、コードが混乱する原因になります。もっと良い方法があります。

整数とポインタを同じオブジェクトに格納したい場合、クリーンで移植可能な方法はunionを使用することです:

union foo {
   int integer_foo;
   void *pointer_foo;
};

これは移植性があり、2つのうち大きい方に必要なストレージのサイズで両方の種類のものを格納できます。常に機能することが保証されています。

5
Perry