46

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

我的猜测是这样做的正确方法是:

printf("%016p", ptr);

这可行,但这个 gcc 抱怨以下消息:

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

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

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

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

所以使用"%p"with sprintf()(或者snprintf(),如果你有的话)打印到一个字符串,然后用前导空格打印字符串填充。

一个问题是没有真正好的方法来确定由"%p".

诚然,这很不方便(尽管您当然可以将其包装在一个函数中)。如果您不需要 100% 的可移植性,我从未使用过将指针投射到unsigned long并打印结果的系统"0x%16lx"不起作用。[更新:是的,我有。64 位 Windows 有 64 位指针和 32 位unsigned long.] (或者您可以使用和计算"0x%*lx"宽度,可能类似于每个字节 2 个十六进制数字。)sizeof (void*) * 2CHAR_BIT > 8

于 2011-08-01T20:59:19.847 回答
5

这个答案类似于前面在https://stackoverflow.com/a/1255185/1905491中给出的答案,但也考虑了可能的宽度(如https://stackoverflow.com/a/6904396/1905491所述,我直到我的答案呈现在它下面才认出来;)。以下片段将在 sane* 机器上将指针打印为 8 个通过 0 的十六进制字符,它们可以用 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 回答
1

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

所以它会变成:

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

正如您的链接已经暗示的那样,行为是未定义的。我认为没有一种可移植的方式来执行此操作,因为 %p 本身取决于您正在使用的平台。您当然可以将指针转换为 int 并以十六进制显示:

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 回答
0

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

于 2015-11-05T16:35:14.563 回答
-1

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

我将有兴趣查看可移植解决方案的答案,因为指针表示并不完全可移植。

于 2009-08-10T14:15:19.767 回答