printf用于显示用0填充的指针的正确用法是什么

时间:2009-08-10 14:08:53

标签: c pointers printf c99

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

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

printf("%016p", ptr);

这有效,但是这个gcc抱怨以下消息:

warning: '0' flag used with ‘%p’ gnu_printf format

我已经用Google搜索了一下,以下主题是关于同一主题的,但并没有真正给出解决方案。

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

阅读它,似乎gcc抱怨的原因是我建议的语法没有在C99中定义。但我似乎无法找到任何其他方式以标准批准的方式做同样的事情。

所以这是双重问题:

  • 我的理解是否正确,C99标准未定义此行为?
  • 如果是这样,是否有标准的,可移植的方式?

9 个答案:

答案 0 :(得分:38)

#include <inttypes.h>

#include <stdint.h>

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

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

答案 1 :(得分:8)

使用:

#include <inttypes.h>

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

或者使用该标头中的宏的另一种变体。

另请注意,printf()的某些实现会在指针前打印一个“0x”;其他人没有(根据C标准,两者都是正确的)。

答案 2 :(得分:5)

打印指针值的唯一可移植方法是使用"%p"说明符,它产生实现定义的输出。 (转换为uintptr_t并使用PRIxPTR可能会有效,但是(a)uintptr_t是在C99中引入的,因此某些编译器可能不支持它,并且(b)它不能保证即使在C99中也存在(可能没有足够大的整数类型来保存所有可能的指针值。

因此,使用"%p"sprintf()(或snprintf(),如果有的话)打印到字符串,然后使用前导空格打印字符串填充。

一个问题是确定由"%p"生成的字符串的最大长度没有很好的方法。

这无疑是不方便的(当然你可以把它包装在一个函数中)。如果您不需要100%的可移植性,我从未使用系统将指针转换为unsigned long并使用"0x%16lx"打印结果将无效。 [更新:是的,我有。 64位Windows有64位指针和32位unsigned long。(或者你可以使用"0x%*lx"计算宽度,可能类似于sizeof (void*) * 2。如果你真的是偏执狂,您可以考虑CHAR_BIT > 8的系统,因此每个字节将获得超过2个十六进制数字。)

答案 3 :(得分:4)

这个答案类似于之前在https://stackoverflow.com/a/1255185/1905491中给出的答案,但也考虑了可能的宽度(由https://stackoverflow.com/a/6904396/1905491概述,直到我的答案在其下面呈现,我才认识到这一点;)。以下剪切将在sane *机器上将指针打印为8个0通过的十六进制字符,其中它们可以由32位表示,16位在64b上,16位在16b系统上。

#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 :(得分:0)

如果将指针强制转换为long类型,则很容易解决。问题是这不适用于所有平台,因为它假定一个指针可以放在一个long内,并且一个指针可以显示为16个字符(64位)。然而,在大多数平台上都是如此。

所以它会变成:

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

答案 5 :(得分:0)

正如您的链接所示,行为未定义。我不认为这是一种可行的方式,因为%p本身取决于您正在处理的平台。您当然可以将指针强制转换为int并以十六进制显示:

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

答案 6 :(得分: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和强制转换(强制转换和格式说明符非常不可移植)仅使用零。

答案 7 :(得分:0)

请注意,如果指针打印时使用&#34; 0x&#34;前缀,你需要替换&#34;%018p&#34;补偿。

答案 8 :(得分:-1)

我通常使用%x来显示指针。我认为它不能移植到64位系统,但它适用于32位。

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