【问题标题】:Where is `%p` useful with printf?`%p` 对 printf 有什么用处?
【发布时间】:2011-01-23 02:17:47
【问题描述】:

毕竟,这两个语句都做同样的事情......

int a = 10;
int *b = &a;
printf("%p\n",b);
printf("%08X\n",b);

例如(使用不同的地址):

0012FEE0
0012FEE0

使用%x 按需要格式化指针很简单,那么%p 选项有什么好的用途吗?

【问题讨论】:

  • 通过使用 '%p' 打印相关变量的地址,“void * 指针参数以十六进制打印(就像通过 %#x 或 %#lx 一样)。”跨度>
  • 在 C++ 中,您可以使用 (void *) 类型转换:参见 stackoverflow.com/questions/5657123/…

标签: c++ c printf


【解决方案1】:

他们不做同样的事情。后面的printf 语句将b 解释为unsigned int,这是错误的,因为b 是一个指针。

指针和unsigned ints 的大小并不总是相同,因此它们不能互换。当它们的大小不同时(这种情况越来越普遍,因为 64 位 CPU 和操作系统变得越来越普遍),%x 将只打印地址的一半。在 Mac(可能还有其他一些系统)上,破坏地址;输出会出错。

始终使用%p 作为指针。

【讨论】:

  • %p 还将为平台指针使用足够的纹理表示。在通常以十六进制表示指针的平台上,只要大小正确,这不会有什么不同,但对于分段架构(你还记得 DOS 吗?)它可能使用段:偏移表示。
  • 还需要使用%p 格式将b 转换为void * - 这是C 语言中少数需要转换的实例之一。
  • "全世界都是 VAX!"综合症。
  • 添加到@AlokSinghal 注释:对于GCC,如果您使用-Wextra 标志编译,您将收到printf 中不正确类型的相应警告。要使警告消失,您需要使用正确的表单并将其转换为 void*,这可能会有所帮助。
【解决方案2】:

至少在一个并不少见的系统上,它们不会打印相同的内容:

~/src> uname -m
i686
~/src> gcc -v
Using built-in specs.
Target: i686-pc-linux-gnu
[some output snipped]
gcc version 4.1.2 (Gentoo 4.1.2)
~/src> gcc -o printfptr printfptr.c
~/src> ./printfptr
0xbf8ce99c
bf8ce99c

例如,请注意指针版本如何添加 0x 前缀。始终使用 %p,因为它知道指针的大小,以及如何最好地将它们表示为文本。

【讨论】:

  • “……这并不少见”。不错:)
【解决方案3】:

您不能依赖 %p 显示 0x 前缀。在 Visual C++ 上,它没有。使用%#p 可移植。

【讨论】:

  • 这是否记录在某处?我找不到任何关于 # 与 %p 一起使用的信息。我查过了:msdn.microsoft.com/en-us/library/8aky45ct(v=vs.71).aspxcplusplus.com/reference/clibrary/cstdio/printf
  • PC-Lint 不喜欢它,但它可以在 Visual Studio 中使用。不幸的是,它前面加了“0X”而不是“0x”,使得实际值难以阅读。这可能是由于缺少 '%P' 变体。总而言之,此格式说明符存在所有“平台相关”实现的问题,即您无法真正控制要获得的内容。我使用 '0x%p' 有可能在开始时得到一个双 0x0X。宁可破坏使用它,因为您确切地知道使用 %x 会得到什么。
  • 这似乎根本无法移植,即使在 VC 版本之间也是如此。例如,VS 2013(12.0.40629.00 更新 5)为“%#p”添加前缀“0X”,但没有为“%p”添加前缀。但是 VC 19.00.23506 没有为“%p”或“%#p”添加前缀。然后 G++ 5.4.0 为 "%p" 和 "%#p" 加上 "0x" 前缀(并且使用 "%#p" 会给出 G++ 警告)。简而言之,你根本不能依赖 this 的格式。
【解决方案4】:

指针的大小可能与int 的大小不同。当您使用%p 时,实现也可以产生比简单的十六进制值更好的地址表示。

【讨论】:

    【解决方案5】:

    x 是无符号十六进制整数(32 位)

    p是指针地址

    printf on the C++ Reference。即使他们两个写的一样,我也会用%p来打印一个指针。

    【讨论】:

    • 是的,我已经浏览了那个页面。我想知道的是你为什么要use %p to print a pointer。无论如何,Peter Hosey 的回答回答了我的疑问。
    【解决方案6】:

    当您需要调试时,使用带有%p 选项的 printf 真的很有帮助。当您有 NULL 值时,您会看到 0x0。

    【讨论】:

    • 在 gcc(至少 4.4.7)上,NULL 值显示为 (nil) - 包括括号。 %p 中似乎有很多特定于实现的变化
    【解决方案7】:

    x 用于以十六进制打印 t 指针参数。

    使用%x 打印的典型地址类似于bfffc6e4,而使用%p 打印的正常地址将是0xbfffc6e4

    【讨论】:

    • 不,%x 用于以十六进制打印unsigned int 类型的值。绝对不能保证 unsigned intvoid * 的大小相同,在代码中假设是一个坏主意。
    猜你喜欢
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    相关资源
    最近更新 更多