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

41 c printf pointers c99

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

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

printf("%016p", ptr);

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

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

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

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

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

所以这是双重问题:

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

APr*_*mer 38

#include <inttypes.h>

#include <stdint.h>

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

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

  • 有趣.这是我第一次看到这个PRIxPTR表示法.这个标准,还是gcc具体?如果标准,哪个标准?C89还是C99? (2认同)
  • C99标准.宏PRIxPTR在<inttypes.h>中定义.uintptr_t类型在<stdint.h>中定义. (2认同)
  • 不应该是'DEAD:BEEF`? (2认同)

Jon*_*ler 8

使用:

#include <inttypes.h>

printf("0x%016" PRIXPTR "\n", (uintptr_t) pointer);
Run Code Online (Sandbox Code Playgroud)

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

还要注意一些在指针前printf()打印' 0x'的实现; 其他人没有(根据C标准,两者都是正确的).


Kei*_*son 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个十六进制数字.)

  • 有一种符合标准的方法,即使用PRIxPTR.如果您选择使用不符合C99的编译器,例如MSVC 2011,则可以使用#ifdef来了解如何执行此操作.我甚至认为MSVC完全符合C89. (2认同)
  • 请注意,在Windows 64位上,“无符号长”类型仍然是32位,尽管指针是64位。因此,在Win64上使用`0x%16lx`将会失败。您将始终获得8个前导零。原则上,使用`unsigned long long`和`0x%16llx`可以工作— MS VS 2015运行时确实支持`ll`修饰符;它还使用“ I64”来指示64位数字([printf()格式说明符](https://msdn.microsoft.com/zh-cn/library/56e442dc.aspx))。使用它之前,请检查早期版本是否支持`ll`。 (2认同)

ste*_*nct 5

这个答案类似于之前在/sf/answers/87862981/ 中给出的答案,但也考虑了可能的宽度(如/sf/answers/483307751/概述的,我直到我的答案在它下面呈现时才认出来;)。以下剪辑将在 sane* 机器上将指针打印为 8 个 0-passed 十六进制字符,其中它们可以用 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);
Run Code Online (Sandbox Code Playgroud)

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

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