web-dev-qa-db-ja.com

intptr_tの用途は何ですか?

私はそれがデータを失うことなくポインタへ/からキャストできる整数型であることを知っていますが、なぜこれをしたいのですか?整数型を持つことは、ポインターを保持するためのvoid*やポインター演算のためのTHE_REAL_TYPE*に比べてどのような利点がありますか?

[〜#〜] edit [〜#〜]
「すでに質問されています」とマークされた質問はこれに答えません。 intptr_tの一般的な置き換えとしてvoid*を使用するのが良い考えであり、そこにある答えは「intptr_tを使用しないでください」と思われるので、私の質問はまだ有効です: intptr_tの良いユースケースになりますか?

24
Baruch

主な理由は、void *でビット単位の操作を実行できないが、intptr_tで同じ操作を実行できることです。

多くの場合、アドレスに対してビット演算を実行する必要がある場合、intptr_tを使用できます。

ただし、ビット単位の操作の場合、最適なアプローチは、対応するunsigneduintptr_tを使用することです。

@ chux による other answer で述べたように、ポインター比較は別の重要な側面です。

また、FWIW、C11標準、§7.20.1.4、

これらのタイプはオプションです。

15
Sourav Ghosh

Intptr_tの用途は何ですか?

使用例:順序の比較。
ポインタの同等性の比較は問題ありません。
その他の比較操作>, <=はUBかもしれません。 C11dr§6.5.8/ 5関係演算子。
だからintptr_t 最初。

[編集]新しい例:ポインターの値でポインターの配列をソートします。

int ptr_cmp(const void *a, const void *b) {
  intptr_t ia = (intptr) (*((void **) a));
  intptr_t ib = (intptr) (*((void **) b));
  return (ia > ib) - (ia < ib);
}

void *a[N];
...
qsort(a, sizeof a/sizeof a[0], sizeof a[0], ptr_cmp);

[以前の例]使用例:ポインターがポインターの配列であるかどうかをテストします。

#define N  10
char special[N][1];

// UB as testing order of pointer, not of the same array, is UB.
int test_special1(char *candidate) {
  return (candidate >= special[0]) && (candidate <= special[N-1]);
}

// OK - integer compare
int test_special2(char *candidate) {
  intptr_t ca = (intptr_t) candidate;
  intptr_t mn = (intptr_t) special[0];
  intptr_t mx = (intptr_t) special[N-1];
  return (ca >= mn) && (ca <= mx);
}

@ M.M でコメントされているように、上記のコードは意図したとおりに動作しない可能性があります。しかし、少なくともUBではありません。 -移植性のない機能。これを使って この問題 を解決したいと思っていました。

7
chux

セマンティックに関する考慮事項もあります。

void*は、何かを指すと想定されています。現代の実用性にもかかわらず、ポインタはメモリアドレスではありません。さて、通常/おそらく/常に(!)は1つを保持しますが、数字ではありません。ポインタです。それは物を指します。

intptr_t ではない。これは整数値であり、ポインターとの間で安全に変換できるため、アンティークAPIに使用したり、pthread関数引数などにパックしたりできます。

だからこそ、intptr_tvoid*、およびジョブに適切なタイプを使用して自己文書化する必要がある理由。

最終的に、ほとんどすべてcouldは整数になります(コンピューターは数字で動作することを思い出してください!)。ポインターは整数である可能性があります。しかし、そうではありません。それらは異なる用途のためのものであるため、ポインターです。そして、理論的には、数値以外のものになる可能性があります。

Uintptr_t型は、メモリ管理コードを書くときに非常に便利です。この種のコードは、ジェネリックポインター(void *)の観点からクライアントとやり取りしたいのですが、内部的にはあらゆる種類の算術演算をアドレスに対して行います。

Char *の観点から操作することで同じことのいくつかを行うことができますが、すべてではなく、結果はpre-Ansi Cのように見えます。

すべてのメモリ管理コードがuintptr_tを使用するわけではありません-例として、BSDカーネルコードはvm_offset_tを同様のプロパティで定義します。しかし、あなたが書いている場合デバッグmallocパッケージ、なぜ独自の型を発明するのですか?

また、printfで%pを使用でき、さまざまなアーキテクチャで16進数でポインターサイズの整数変数を印刷する必要があるコードを記述している場合にも役立ちます。

同じキャストで符号付きと整数サイズを変更することに関する恐ろしい警告を避けるために、おそらくキャスト時のウェイステーションとして以外は、inttptr_tはあまり有用ではないと思います。 (関連するすべてのアーキテクチャで-Wall -Werrorを渡すポータブルコードの作成は、少し苦労する場合があります。)

6
Arlie Stephens