web-dev-qa-db-ja.com

0でパディングされたポインターを表示するためのprintfの適切な使用法

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標準で定義されていないという私の理解は正しいですか?
  • もしそうなら、これを行う標準の承認されたポータブルな方法はありますか?
42
Florian

_#include <inttypes.h>_

_#include <stdint.h>_

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

ただし、実装で定義された方法でポインタを出力しません(8086セグメントモードの場合は_DEAD:BEEF_と表示されます)。

38
AProgrammer

使用する:

_#include <inttypes.h>

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

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

また、printf()の一部の実装では、ポインタの前に '_0x_'が出力されます。他の人はそうしません(そして両方ともC標準に従って正しいです)。

8

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

そのため、_"%p"_をsprintf()(またはsnprintf()(ある場合)とともに使用して文字列に出力し、その後に先行空白で文字列のパディングを出力します。

1つの問題は、_"%p"_によって生成される文字列の最大長を決定する本当に良い方法がないことです。

これは確かに不便です(もちろん、関数でラップすることもできます)。 100%の移植性が必要ない場合、_unsigned long_へのポインターをキャストするシステムを使用したことがなく、_"0x%16lx"_を使用して結果を印刷しても機能しません。 [[〜#〜] update [〜#〜]:はい、持っています。 64ビットWindowsには64ビットポインターと32ビット_unsigned long_があります。](または、_"0x%*lx"_を使用して幅を計算できます。おそらくsizeof (void*) * 2のようになります。本当に偏執的で、_CHAR_BIT > 8_であるシステムを考慮することができるので、バイトあたり2桁を超える16進数が得られます。)

5
Keith Thompson

この回答は、以前に 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は最小値よりも大きくなりますが、最小値を使用しない実装はないと思います。

4
stefanct

多分これは面白いでしょう(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とキャスト(キャストとフォーマット指定子は非常に移植性が低い)を使用すると、ゼロのみが使用されます。

0
Rodrigo Queiro

ポインターが "0x"プレフィックスで印刷される場合は、補正するために "%018p"に置き換える必要があることに注意してください。

0
Jerry Miller

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

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

printf("%016lx", (unsigned long) ptr);
0
AnthonyLambert

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

printf("0x%016lx", (unsigned long)ptr);
0
groovingandi