回答:
異なるプラットフォーム間での形式のばらつきやバリエーションを気にしないと仮定すると、最も簡単な答えは標準%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 *
特定のメモリ位置のアドレスのビット表現が同じメモリ位置の「その他のポインタ」アドレスと異なるマシンでは問題になります。これは、バイトアドレス指定されたマシンではなく、ワードアドレス指定されたマシンです。このようなマシンは一般的ではありません(おそらく利用できません)が、大学の後に私が最初に取り組んだマシンはそのようなマシンの1つ(ICL Perq)でした。
の実装定義の動作に満足できない場合は、代わりに%p
C99 <inttypes.h>
を使用しuintptr_t
ます。
printf("0x%" PRIXPTR "\n", (uintptr_t)your_pointer);
これにより、表現を自分に合わせて微調整できます。数字が均一に同じ高さになるように16進数字を大文字にすることを選択しました。これにより、開始時に特徴的なディップが0xA1B2CDEF
表示されます。これは0xa1b2cdef
、数値に沿って上下にディップするのとは異なります。ただし、非常に広い範囲で選択できます。(uintptr_t)
それはコンパイル時にフォーマット文字列を読み取ることができたときにキャストが明確にGCCで推奨されています。キャストをリクエストするのは正しいと思いますが、ほとんどの場合、警告を無視してそれを回避する人もいると思います。
ケレックはコメントで尋ねています:
標準的なプロモーションと可変引数について少し混乱しています。すべてのポインターがvoid *に標準的に昇格されますか?それ以外の場合、
int*
たとえば、2バイトでvoid*
4バイトだった場合、引数から4バイトを読み取るのは明らかにエラーでしょう。
私は、すべてのオブジェクトポインターは同じサイズでなければならず、異なるサイズであっvoid *
てint *
はならないというC標準の幻想の下にありました。しかし、私がC99標準の関連セクションだと思うのはそれほど強調されていません(私が提案したことが真である実装は実際には偽ですが)。
§6.2.5タイプ
¶26voidへのポインタは、文字型へのポインタと同じ表現および配置要件を持たなければならない。39)同様に、互換性のある型の修飾されたバージョンまたは修飾されていないバージョンへのポインターは、同じ表現と配置の要件を持たなければなりません。構造体型へのすべてのポインタは、互いに同じ表現と配置の要件を持たなければなりません。共用体型へのすべてのポインタは、相互に同じ表現と配置の要件を持たなければなりません。他の型へのポインターは、同じ表現または配置要件を持つ必要はありません。
39)同じ表現と配置の要件は、関数への引数、関数からの戻り値、および共用体のメンバーとしての互換性を暗示することを意図しています。
(C11は、§6.2.5、¶28、および脚注48でもまったく同じです。)
したがって、構造体へのすべてのポインターは互いに同じサイズである必要があり、ポインターが指す構造体の配置要件が異なる場合でも、同じ配置要件を共有する必要があります。組合についても同様です。文字ポインターとvoidポインターは、サイズと配置の要件が同じでなければなりません。int
(意味unsigned int
とsigned int
)のバリエーションへのポインタは、互いに同じサイズと配置要件を持っている必要があります。他のタイプについても同様です。しかし、C標準は正式にそれを述べていませんsizeof(int *) == sizeof(void *)
。まあ、SOは仮定を検証させるのに適しています。
C規格では、関数ポインタをオブジェクトポインタと同じサイズにする必要はありません。これは、DOSのようなシステムで異なるメモリモデルを壊さないために必要でした。そこでは、16ビットのデータポインターを32ビットの関数ポインター、またはその逆にすることができます。これが、C標準で、関数ポインターをオブジェクトポインターに、またはその逆に変換できることを義務付けていない理由です。
幸運なことに(POSIXを対象とするプログラマーにとって)、POSIXは侵害に踏み込み、関数ポインターとデータポインターが同じサイズであることを義務付けています。
§2.12.3 ポインタ型
すべての関数ポインタ型は、voidへの型ポインタと同じ表現を持つ必要があります。関数ポインタをに変換しても
void *
、表現は変更されません。そのvoid *
ような変換の結果の値は、情報を失うことなく、明示的なキャストを使用して、元の関数ポインター型に戻すことができます。注:ISO C標準ではこれは必須ではありませんが、POSIX準拠には必須です。
したがって、のようなvoid *
可変関数へのポインタを渡す場合、コードでの最大の信頼性のためにへの明示的なキャストが強く推奨されるようprintf()
です。POSIXシステムでは、印刷のために関数ポインターをvoidポインターにキャストしても安全です。他のシステムでは、それを行うことが必ずしも安全であるとは限らvoid *
ず、キャストなしで以外にポインタを渡すことも必ずしも安全ではありません。
dlsym()
代わりにほとんどの要件が関数に移動したことに注意してください。ある日、変更について書こうと思いますが、「1日」は「今日」ではありません。
void *
か?うーん、ここにコメントが表示されます。one-wat変換のみが必要なため(への関数ポインターvoid *
)、それは機能しますか?
void *
、情報を失わずに変換したりできることを保証していません。実用的には、関数ポインターのサイズがオブジェクトポインターのサイズと同じではないマシンはほとんどありません。変換が問題となるマシンで関数ポインタを出力する方法は、この標準では提供されていないと思います。
p
ポインターを出力するための変換指定子です。これを使って。
int a = 42;
printf("%p\n", (void *) &a);
キャストの省略は未定義の動作であり、p
変換指定子を使用した印刷は実装定義の方法で行われることに注意してください。
使用%p
「ポインタ」のため、および*何かを使用しないでください。ポインタを特定のタイプの整数のように扱うことが許可されていることは、標準では保証されていないため、実際には、整数形式で未定義の動作が発生します。(例えば、%u
期待しunsigned int
ている場合、しかし、何void*
よりも、異なるサイズまたは位置合わせ要件を有していますunsigned int
?)
*)[Jonathanの細かい答えを参照してください!]の代わりに%p
、C99で追加されたからのポインター固有のマクロを使用できます<inttypes.h>
。
すべてのオブジェクトポインターはvoid*
Cで暗黙的に変換可能ですが、可変引数としてポインターを渡すには、明示的にキャストする必要があります(任意のオブジェクトポインターは変換可能で、voidポインターとは同一ではないため)。
printf("x lives at %p.\n", (void*)&x);
void *
(printf()
可変関数であるため、技術的には明示的なキャストが必要です)。関数ポインタは必ずしもに変換できるとは限りませんvoid *
。
void *
、関数ポインターを損失せずに関数ポインターに変換したり、関数ポインターに戻したりする必要はありません。幸いにも、POSIXはそれを明示的に要求します(標準Cの一部ではないことに注意してください)。したがって、実際にはそれを回避できます(に変換void (*function)(void)
しvoid *
てに戻しますvoid (*function)(void)
)が、厳密にはC標準では必須ではありません。
%u
!
%u
と%lu
に間違っているすべてのマシンではなく、いくつかのマシン。の仕様はprintf
、渡されたタイプがフォーマット指定子で必要なタイプと一致しない場合の動作が定義されていないことを明確にしています。タイプのサイズが一致するかどうか(マシンに応じてtrueまたはfalseになる可能性があります)は関係ありません。それは一致しなければならないタイプであり、決して一致しません。
他の(非常に良い)答えの代わりに、あなたはにキャストできuintptr_t
たりintptr_t
(からstdint.h
/ inttypes.h
)と対応する整数変換指定子を使用します。これにより、ポインタのフォーマット方法の柔軟性が高まりますが、厳密に言えば、これらのtypedefを提供するための実装は必要ありません。
#include <stdio.h> int main(void) { int p=9; int* m=&s; printf("%u",m); }
、それが使用して変数のアドレスを印刷する未定義の動作である%u
書式指定子が?ほとんどの場合、変数のアドレスは正なので、%u
代わりに使用でき%p
ますか?
%u
形式であり、unsigned int
へのポインター引数と共に使用することはできませんprintf
。
%x
または%X
またはを使用できます%p
。それらはすべて正しいです。
%x
場合、アドレスは小文字で指定されます。次に例を示します。a3bfbc4
%X
場合、アドレスは大文字で指定されます。次に例を示します。A3BFBC4
これらは両方とも正しいです。
を使用している場合、%x
または%X
アドレスの6つの位置を考慮している場合、および使用し%p
ている場合、アドレスの8つの位置を考慮しています。例えば:
void*
ますか?それ以外の場合、int*
たとえば、2バイトでvoid*
4バイトだった場合、引数から4バイトを読み取るのは明らかにエラーでしょう。