46

C では、printf を使用してポインターを表示したいのですが、ポインターが適切に整列するように、ポインターを 0 で埋めたいと考えています。

私の推測では、これを行う適切な方法は次のとおりでした。

printf("%016p", ptr);

これは機能しますが、この gcc には次のメッセージが表示されます。

警告: '%p' gnu_printf フォーマットで使用される '0' フラグ

私はそれについて少しグーグルで調べました.次のスレッドは同じトピックに関するものですが、実際には解決策を提供していません.

http://gcc.gnu.org/ml/gcc-bugs/2003-05/msg00484.html

それを読むと、gcc が文句を言うのは、私が提案した構文が C99 で定義されていないことが原因のようです。しかし、標準的に承認された方法で同じことを行う他の方法を見つけることができないようです。

だからここに二重の質問があります:

  • この動作は C99 標準で定義されていないという私の理解は正しいですか?
  • もしそうなら、これを行うための標準的に承認されたポータブルな方法はありますか?
4

9 に答える 9

41

#include <inttypes.h>

#include <stdint.h>

printf("%016" PRIxPTR "\n", (uintptr_t)ptr);

ただし、実装で定義された方法でポインターを出力しません ( DEAD:BEEF8086 セグメント化モードの場合)。

于 2009-08-10T14:24:10.253 に答える
9

使用する:

#include <inttypes.h>

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

または、そのヘッダーのマクロの別のバリアントを使用します。

また、ポインタの前にprintf()' ' を出力する実装もあることに注意してください。0x他のものはそうではありません (両方とも C 標準に従って正しいです)。

于 2009-08-10T14:47:40.963 に答える
5

この回答は、以前にhttps://stackoverflow.com/a/1255185/1905491で示したものと似ていますが、可能な幅も考慮しています ( https://stackoverflow.com/a/6904396/1905491で概説されているように、私の答えがその下に表示されるまで認識しませんでした;)。次の切り取りは、sane* マシンでは 8 個の 0 を通過した 16 進文字としてポインターを出力し、32 ビットで表現できます。64b システムでは 16 個、16b システムでは 4 個です。

#include <inttypes.h>
#define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))

printf("0x%0*" PRIxPTR, PRIxPTR_WIDTH, (uintptr_t)pointer);

次の引数で幅を取得するためにアスタリスク文字を使用していることに注意してください。これは C99 (おそらく以前?) にありますが、「実際には」めったに見られません。p後者は実装定義であるため、これは変換を使用するよりもはるかに優れています。

* 標準uintptr_tでは最小値よりも大きくすることができますが、最小値を使用しない実装はないと思います。

于 2013-01-01T18:04:31.960 に答える
5

ポインター値を出力する唯一の移植可能"%p"な方法は、実装定義の出力を生成する指定子を使用することです。(変換しuintptr_tて使用するPRIxPTRことはうまくいく可能性がありますが、(a) uintptr_tC99 で導入されたため、一部のコンパイラはそれをサポートしていない可能性があり、(b) C99 でも存在することが保証されていません (十分な大きさの整数型がない可能性があります)すべての可能なポインター値を保持します。

したがって、"%p"with sprintf()(またはsnprintf()、ある場合は ) を使用して文字列に出力し、先頭の空白で文字列のパディングを出力します。

問題の 1 つは、 によって生成される文字列の最大長を判断する適切な方法がないこと"%p"です。

これは確かに不便です (もちろん、関数でラップすることはできます)。100% の移植性が必要ない場合は、ポインターをキャストしunsigned longて結果を出力するシステムを使用した"0x%16lx"ことがありません。[更新: はい、あります。64 ビットの Windows には 64 ビットのポインターと 32 ビットのがありunsigned longます。1 バイトあたり 2 桁の 16 進数。)"0x%*lx"sizeof (void*) * 2CHAR_BIT > 8

于 2011-08-01T20:59:19.847 に答える
1

ポインタを long 型にキャストすると解決しやすいです。問題は、ポインターが long 内に収まり、ポインターが 16 文字 (64 ビット) で表示できると想定しているため、これがすべてのプラットフォームで機能するとは限らないことです。ただし、これはほとんどのプラットフォームに当てはまります。

したがって、次のようになります。

printf("%016lx", (unsigned long) ptr);
于 2009-08-10T14:20:06.127 に答える
0

リンクがすでに示唆しているように、動作は未定義です。%p 自体は作業しているプラ​​ットフォームに依存するため、これを行う移植可能な方法はないと思います。もちろん、ポインターを int にキャストして 16 進数で表示することもできます。

printf("0x%016lx", (unsigned long)ptr);
于 2009-08-10T14:21:43.487 に答える
0

たぶんこれは興味深いでしょう (32 ビット Windows マシンから、mingw を使用):

rjeq@RJEQXPD /u
$ cat test.c
#include <stdio.h>

int main()
{
    char c;

    printf("p: %016p\n", &c);
    printf("x: %016llx\n", (unsigned long long) (unsigned long) &c);

    return 0;
}

rjeq@RJEQXPD /u
$ gcc -Wall -o test test.c
test.c: In function `main':
test.c:7: warning: `0' flag used with `%p' printf format

rjeq@RJEQXPD /u
$ ./test.exe
p:         0022FF77
x: 000000000022ff77

ご覧のとおり、%p バージョンでは、ポインタのサイズまでゼロが埋め込まれ、指定されたサイズまでスペースが埋められますが、%x とキャスト (キャストとフォーマット指定子は移植性が非常に低い) を使用すると、ゼロのみが使用されます。

于 2009-08-10T14:23:36.400 に答える
-1

私は通常 %x を使用してポインターを表示します。これは 64 ビット システムには移植できないと思いますが、32 ビット システムでは問題なく動作します。

ポインター表現は完全に移植可能ではないため、移植可能なソリューションにどのような答えがあるかを知りたいと思います。

于 2009-08-10T14:15:19.767 に答える