web-dev-qa-db-ja.com

フォーマット指定子を印刷ポインターまたはアドレスに修正しますか?

変数のアドレスを表示するためにどの形式指定子を使用すればよいですか?私は下のロットの間で混乱しています。

%u - 符号なし整数

%x - 16進値

%p - 無効ポインタ

住所を印刷するのに最適な形式はどれですか。

156
San

最も単純な答えは、プラットフォームごとの形式の違いやバリエーションを気にしないと仮定すると、標準の%p表記です。

C99規格(ISO/IEC 9899:1999)は§7.19.6.1¶8で述べています。

p引数はvoidへのポインタです。ポインターの値は、実装定義の方法で、一連の印刷文字に変換されます。

(C11 - ISO/IEC 9899:2011 - 情報は§7.21.6.1¶8にあります。)

いくつかのプラットフォームでは、先頭に0xが含まれ、その他では含まれません。また、文字は小文字でも大文字でもかまいません。C標準では、16進数であることを定義していません実装されていない場合は実装されていません。

ポインタを(void *)キャストで明示的に変換する必要があるかどうかについては、ある程度議論の余地があります。これは明示的なもので、通常は良いものです(だから私はそうしています)。そして標準は '引数はvoidへのポインタでなければならない'と言っています。ほとんどのマシンでは、明示的なキャストを省略することで解決します。しかし、与えられたメモリ位置のchar *アドレスのビット表現が 'その他のポインタ'のアドレスと異なる場合は、問題になります。同じメモリ位置これは、バイトアドレスではなくワードアドレスのマシンになります。そのようなマシンは最近では一般的ではない(おそらく利用できない)が、大学の後に私が最初に作業したマシンはそのようなものだった(ICL Perq)。

実装定義の%pの振る舞いに満足できない場合は、代わりにC99 <inttypes.h>およびuintptr_tを使用してください。

printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);

これにより、表現を自分に合うように微調整できます。数字が一様に同じ高さになるように16進数を大文字にし、0xA1B2CDEFの先頭の特性dipが表示されるようにしました。数字に沿って上下する0xa1b2cdefとは異なります。あなたの選択は、しかし、非常に広い範囲内で。 (uintptr_t)キャストは、コンパイル時にフォーマット文字列を読み取ることができる場合にGCCによって明確に推奨されています。キャストを要求するのは正しいと思いますが、警告を無視してほとんどの場合それを回避する人がいると確信しています。


Kerrekはコメントで尋ねます:

標準的なプロモーションとさまざまな議論について少し混乱しています。すべてのポインターは標準でvoid *にプロモートされますか?そうではなく、int*が2バイトで、void*が4バイトの場合、引数から4バイトを読み取るのは明らかにエラーです。

私は、C標準ではすべてのオブジェクトポインタは同じサイズでなければならないと述べているので、void *int *を異なるサイズにすることはできないと錯覚しました。しかし、C99標準の関連するセクションはそれほど強調されていません(私が提案したものが真である実装が実際には偽であることはわかりませんが)。

§6.2.5型

¶26voidへのポインタは、文字型へのポインタと同じ表現および整列要件を持たなければならない。39) 同様に、互換性のある型の修飾または非修飾バージョンへのポインタは、同じ表現と整列の要件を持つものとします。構造体型へのすべてのポインタは、互いに同じ表現および配置要件を持つものとします。共用体型へのすべてのポインタは、互いに同じ表現および整列の要件を持つものとします。他の型へのポインタは、同じ表現または配置要件を持つ必要はありません。

39) 同じ表現と整列の要件は、関数への引数、関数からの戻り値、および共用体のメンバーとしての互換性を意味することを意図しています。

(C11は、§6.2.5、¶28、および脚注48でも同じです。)

したがって、構造体へのすべてのポインターは互いに同じサイズでなければならず、ポインターが指す構造体には異なる整列要件があっても、同じ整列要件を共有しなければなりません。組合も同様です。文字ポインタと無効ポインタは、同じサイズと配置要件を持っていなければなりません。 intのバリエーションへのポインタ(unsigned intsigned intを意味する)は、互いに同じサイズと配置の要件を持つ必要があります。他のタイプについても同様です。しかし、C標準は正式にはsizeof(int *) == sizeof(void *)とは言っていません。まあ、SOはあなたがあなたの仮定を詳しく調べるのに良いです。

C標準では、関数ポインターをオブジェクトポインターと同じサイズにする必要はありません。それはDOSのようなシステムで異なるメモリモデルを壊さないために必要でした。そこに16ビットのデータポインタと32ビットの関数ポインタ、またはその逆を持つことができます。これが、C標準が関数ポインタとオブジェクトポインタの間の変換、およびその逆の変換を義務付けていない理由です。

幸いなことに(POSIXをターゲットにしているプログラマーのために)、POSIXは違反に踏み込んで、関数ポインタとデータポインタが同じサイズであることを強制します:

§2.12.3 ポインタ型

すべての関数ポインタ型は、voidへの型ポインタと同じ表現になります。関数ポインタをvoid *に変換しても表現は変わりません。このような変換の結果得られるvoid *値は、情報を失うことなく、明示的なキャストを使用して元の関数ポインタ型に戻すことができます。

注:ISO C規格ではこれは要求されていませんが、POSIXへの準拠に必要です。

そのため、printf()のような可変関数へのポインタを渡す場合、コード内での信頼性を最大限に高めるために、void *への明示的なキャストが強く推奨されるようです。 POSIXシステムでは、関数ポインタをvoidポインタにキャストして印刷するのが安全です。他のシステムでは、必ずしもそうすることが安全であるとは限らず、また、キャストなしでvoid *以外のポインターを渡すことも必ずしも安全ではありません。

194

pは、印刷ポインタへの変換指定子です。これを使って。

int a = 42;

printf("%p\n", (void *) &a);

キャストを省略することは未定義の動作であり、p変換指定子を使用した印刷は実装定義の方法で行われることを忘れないでください。

39
ouah

"pointer"には%pを使用し、それ以外は使用しないでください*。標準では、ポインタを特定の整数型のように扱うことが許可されているとは保証されていないので、実際には整数形式では未定義の動作になります。 (例えば、%uunsigned intを期待していますが、void*unsigned intと異なるサイズまたはアライメント要件を持っている場合はどうなりますか?)

*)[Jonathanのすばらしい答えを参照してください。] %pの代わりに、あなたはcan C99で追加された<inttypes.h>からのポインタ固有のマクロを使うことができます。

すべてのオブジェクトポインタはC言語で暗黙のうちにvoid*に変換可能ですが、ポインタを可変引数として渡すには明示的にキャストする必要があります(任意のオブジェクトポインタは変換可能のみであり、---はできません同一無効ポインタへ):

printf("x lives at %p.\n", (void*)&x);
26
Kerrek SB

他の(非常に良い)答えに代わるものとして、(uintptr_t/intptr_tから)stdint.hまたはinttypes.hにキャストして、対応する整数変換指定子を使用することができます。これにより、ポインタのフォーマット方法の柔軟性が高まりますが、厳密に言えば、これらのtypedefを提供するための実装は必要ありません。

8
R..