uintptr_tデータ型とは


回答:


199

uintptr_tデータポインタを格納できる符号なし整数型です。これは通常、ポインタと同じサイズであることを意味します。

オプションで、C ++ 11以降の標準で定義されています。

アーキテクチャーのポインター型を保持できる整数型が必要になる一般的な理由は、ポインターに対して整数固有の操作を実行するか、整数の「ハンドル」として提供してポインターの型を不明瞭にすることです。

編集:スティーブ・ジェソップがあなたの教育的なタイプの別の答えでいくつかの非常に興味深い追加の詳細(私が盗むことはありません)を持っていることに注意してください:)


53
size_t最大のオブジェクトのサイズを保持するのに十分である必要があるだけで、ポインタよりも小さいことに注意してください。これは、8086(16ビットのようなセグメント化されたアーキテクチャ上で予想されるsize_tが、32ビットvoid*
MSalters

3
2つのポインタの差を表すために、あなたが持っていますptrdiff_tuintptr_tそのためのものではありません。
2009

3
@jalf:違いはありますが、距離の場合は、符号なしの型が必要になります。
Drew Dormann、

C ++ 11でさえ、uintptr_t定義は明らかに義務ではない(したがって標準ではない)。cplusplus.com/reference/cstdint(Steve Jessopの回答からヒントを得た)
Antonio

2
@MarcusJ unsigned intは通常、十分な大きさではありません。しかし、それは十分に大きいかもしれません。このタイプは、特にすべての「仮定」を削除するために存在ます。
Drew Dormann、2015年

239

質問が出されたときの最初のことuintptr_tは、C ++ ではありませんでした。これ<stdint.h>は、オプションの型としてC99にあります。多くのC ++ 03コンパイラはそのファイルを提供しています。また、C ++ 11のにも<cstdint>あります。ここでも、これはオプションであり、定義ではC99を参照します。

C99では、「voidへの有効なポインターをこの型に変換でき、その後voidへのポインターに変換でき、結果が元のポインターと同じになるプロパティを持つ符号なし整数型」として定義されています。

これは、それが言っていることを意味すると考えてください。サイズについては何も言っていません。

uintptr_tと同じサイズの場合がありvoid*ます。大きいかもしれません。このようなC ++実装はひどいアプローチになっていますが、おそらくそれはもっと小さいかもしれません。たとえばvoid*、32ビットの仮想プラットフォームで仮想アドレス空間が24ビットしか使用されてuintptr_tいない場合、要件を満たす24ビットを使用できます。なぜ実装がそれを行うのかはわかりませんが、標準では許可されています。


8
"<stdint.h>"をありがとう。uintptr_t宣言が原因で、アプリケーションがコンパイルされませんでした。しかし、私があなたのコメントを読んだとき、私は "#include <stdint.h>"を追加し、ええ、今はそれが機能します。ありがとう!
JavaRunner 14

2
たとえば、他の用途の中で整列メモリ割り当てるには?
legends2k

4
ポインターをintにキャストするもう1つの一般的な使用例は、ポインターを非表示にする不透明なハンドルを作成することです。これは、APIからオブジェクトへの参照を返し、ライブラリに対してオブジェクトをプライベートに保ち、アプリケーションがオブジェクトにアクセスできないようにする場合に役立ちます。その後、アプリケーションはAPIを使用してオブジェクトの操作を実行する必要があります
Joel Cunningham

3
@JoelCunningham:それは機能しますが、を使用することと実際には何も変わりませんvoid*。ただし、特に、変換されたポインターではなく、整数のハンドルにすぎないものを使用するように変更したい場合は、将来の方向性に影響します。
スティーブジェソップ2016

2
@CiroSantilli烏竜事件2016六四事件法轮功一般的な使用例は、int *だけをAPIに渡して、一般的なデータにvoid *を期待することです。キーストロークを節約しますtypedef struct { int whyAmIDoingThis; } SeriouslyTooLong; SeriouslyTooLong whyAmNotDoneYet; whyAmINotDoneYet.whyAmIDoingThis = val; callback.dataPtr = &whyAmINotDoneYet;。代わりに:callback.dataPtr = (void*)val。反対に、もちろんそれを取得void*してにキャストし直す必要がありintます。
Francesco Dondi 2017

19

これは、ポインタのサイズとまったく同じ符号なし整数型です。たとえば、すべてのビットを反転する(理由は問わない)など、ポインターを使用して異常なことを行う必要がある場合は常にuintptr_t、それをキャストして通常の整数として操作してから、キャストバックします。


6
もちろんそれは可能ですが、それはもちろん未定義の動作です。私は、uintptr_tへのキャストの結果を使用して実行できる唯一のことは、それを変更せずに渡し、それをキャストバックすることです。それ以外はすべてUBです。
sleske 2011年

ビットをいじる必要がある場合があり、それは通常コンパイラエラーを生成します。一般的な例は、特定のビデオおよびパフォーマンスが重要なアプリケーションに16バイト境界で整列されたメモリを適用することです。stackoverflow.com/questions/227897/…–
クラウド、

3
@sleskeは真実ではありません。自己整合型のマシンでは、ポインタの最下位2ビットはゼロになります(アドレスが4または8の倍数であるため)。私は..圧縮データにこれを悪用したプログラムを見てきました
saadtaame

3
@saadtaame:これはC標準によるとUBであることを指摘しました。これは、一部のシステムでは定義できないという意味ではありません。コンパイラとランタイムは、標準CのUBである何かに対して特定の動作を自由に定義できます。したがって、矛盾はありません:-)。
sleske

2
ポインタのサイズとは必ずしも正確ではありません。すべての標準的な保証は、void*ポインター値を変換して元のポインターにuintptr_t戻す値を再び生成するvoid*ことです。uintptr_tは通常と同じサイズですがvoid*、これは保証されていません。また、変換された値のビットが特定の意味を持つことも保証されていません。また、情報を失うことなく、関数へのポインターへの変換値を保持できるという保証はありません。最後に、それが存在することは保証されていません。
キーストンプソン

15

「uintptr_tデータ型とは」という部分には、すでに多くの良い答えがあります。「何のために使えるの?」に取り組みます。この投稿に含まれています。

主にポインターのビット単位の操作用。C ++では、ポインタに対してビット演算を実行できないことに注意してください。理由については、Cでポインターに対してビット単位の操作を実行できない理由を参照してください。これを回避する方法はありますか?

したがって、ポインタに対してビット単位の演算を行うには、ポインタをunitpr_t型にキャストしてからビット単位の演算を実行する必要があります。

これは、XORリンクリストに格納するためにビット単位の排他的または2つのポインターを実行するように記述した関数の例です。これにより、二重リンクリストのように双方向にトラバースできますが、各ノードに2つのポインターを格納するペナルティはありません。 。

 template <typename T>
 T* xor_ptrs(T* t1, T* t2)
 {
     return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(t1)^reinterpret_cast<uintptr_t>(t2));
  }

1
ビット演算以外に、オブジェクトカウントではなくアドレスに基づくセマンティクスが必要な場合にも便利です。
アレックス

4

別のネクロマンサーバッジを取得するリスクを冒して、uintptr_t(またはintptr_t)の非常に優れた使用法を1つ追加します。これにより、テスト可能な埋め込みコードが作成されます。私は主に、さまざまなアームと現在テンシリカのプロセッサをターゲットにした埋め込みコードを書いています。これらにはさまざまなネイティブバス幅があり、テンシリカは実際にはハーバードアーキテクチャであり、コードバスとデータバスが異なる可能性があります。私はコードの多くにテスト駆動開発スタイルを使用しています。つまり、私が書くすべてのコードユニットに対してユニットテストを実行しています。実際のターゲットハードウェアでユニットテストを行うのは面倒なので、通常はCeedlingとGCCを使用して、WindowsまたはLinuxのIntelベースのPCですべてを書き込みます。そうは言っても、埋め込まれたコードの多くは、ビットのいじりやアドレス操作を伴います。私のIntelマシンのほとんどは64ビットです。したがって、アドレス操作コードをテストする場合は、数学を実行するための汎用オブジェクトが必要です。したがって、uintptr_tは、ターゲットハードウェアにデプロイする前に、コードをデバッグするマシンに依存しない方法を提供します。別の問題は、一部のマシンまたは一部のコンパイラのメモリモデルでさえ、関数ポインタとデータポインタの幅が異なります。これらのマシンでは、コンパイラーは2つのクラス間のキャストを許可しないこともありますが、uintptr_tはどちらも保持できるはずです。


関連するかどうかわからない...「不透明なtypedef」を試しましたか?ビデオ:youtube.com/watch
v

@sleske Cで使用できることを願っていますが、stdint.hを使用することは、何もないよりはましです。(また強く型付けされたが、ほとんどのデバッガは、どのような方法でそれらを考え出すの良い仕事をする列挙型を望む)
bd2357
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.