什么是正确使用printf来显示用0填充的指针

在C中,我想使用printf来显示指针,并使它们正确排列,我想用0填充它们。

我的猜测是,正确的做法是:

  printf(“%016p”,ptr); 

这工作,但这个海湾合作委员会抱怨以下消息:

 警告:与'%p'gnu_printf格式一起使用'0'标志 

我已经google了一下,下面的线程是在同一个主题,但并没有真正给出解决scheme。

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

阅读它,似乎gcc抱怨的原因是我提出的语法没有在C99中定义。 但我似乎无法find任何其他方式以标准认可的方式来做同样的事情。

所以这里是双重的问题:

  • 我的理解是正确的,这种行为不是由C99标准定义的?
  • 如果是这样,是否有一个标准的批准,便携式的方式呢?

#include <inttypes.h>

#include <stdint.h>

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

但是它不会以实现定义的方式打印指针( DEAD:BEEF 8086分段模式的DEAD:BEEF )。

使用:

 #include <inttypes.h> printf("0x%016" PRIXPTR "\n", (uintptr_t) pointer); 

或者使用该头部的macros的另一个变种。

还要注意一些printf()实现在指针前面打印一个' 0x ' 别人没有(根据C标准都是正确的)。

打印指针值的唯一便携方法是使用"%p"说明符,它生成实现定义的输出。 (转换为uintptr_t并使用PRIxPTR很可能会工作,但(a) uintptr_t是在C99中引入的,因此有些编译器可能不支持它,(b)即使在C99中也不能保证存在(可能不是整数types足够大以容纳所有可能的指针值。

因此,使用sprintf() (或snprintf() ,如果有的话)的"%p"打印到一个string,然后打印string填充前导空白。

一个问题是,确定由"%p"生成的string的最大长度没有真正的好方法。

这当然是不方便的(当然,你可以把它包装在一个函数中)。 如果你不需要100%的可移植性,我从来没有使用过将指针转换为unsigned long的系统,而使用"0x%16lx"打印结果将不起作用。 (或者你可以使用"0x%*lx"来计算宽度,可能类似于sizeof (void*) * 2 ,如果你确实是偏执的话,那么你可以考虑CHAR_BIT > 8系统,比每个字节2个hex数字)。

这个答案类似于之前在https://stackoverflow.com/a/1255185/1905491中给出的答案,但也考虑到了可能的宽度(如https://stackoverflow.com/a/6904396/1905491所述,其中I直到我的答案被呈现在它下面才认出);; 下面的内容将把指针打印为8位0-hex字符,它们可以由32位,64位和16位系统中的16位来表示。

 #include <inttypes.h> #define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2)) printf("0x%0*" PRIxPTR, PRIxPTR_WIDTH, (uintptr_t)pointer); 

请注意使用星号字符来获取宽度的下一个参数,这是在C99(可能之前?),但很less见“野外”。 这比使用p转换更好,因为后者是实现定义的。

*标准允许uintptr_t大于最小值,但是我认为没有使用最小值的实现。

如果将指针指向长types,则很容易解决。 问题是这不适用于所有的平台,因为它假定一个指针可以放在一个长的内部,并且一个指针可以以16个字符(64位)显示。 但是在大多数平台上都是如此。

所以它会变成:

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

由于您的链接已经build议,行为是不确定的。 我不认为有这样做的可移植方式,因为%p本身取决于您正在使用的平台。 你当然可以将指针转换为一个int值并以hex显示:

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

也许这将是有趣的(从一个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和强制转换(强制转换和格式说明符是非常不可移植的)只使用零。

请注意,如果指针以“0x”前缀打印,则需要replace“%018p”进行补偿。

我通常使用%x来显示指针。 我想这不是可移植到64位系统,但它对32位工作正常。

因为指针表示不完全是可移植的 ,所以我会对看到便携式解决scheme的答案感兴趣。