正确的格式说明符打印指针(地址)?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (182)

我应该使用哪种格式说明符来打印变量的地址?我很困惑下面的很多。

%u - 无符号整数 %x - 十六进制值 %p - void指针

这将是打印地址的最佳格式?

提问于
用户回答回答于

标准%p符号。

C99标准(ISO / IEC 9899:1999)在§7.19.6.1¶8中说:

p这个论点应该是一个指针void。指针的值以实现定义的方式转换为打印字符序列。

(在C11 - ISO / IEC 9899:2011中 - 信息在§7.21.6.1¶8中。)

在一些平台上,这将包括一个领先的0x和其他的平台,并且这些字母可以是小写或大写字母,并且C标准甚至没有定义它应该是十六进制输出,尽管我知道没有实现的地方没有。

对于是否应该明确地转换指针与(void *)演员阵线来说,有些争议。它是明确的,通常是好的(所以我就是这么做的),标准说'争论应该是一个指针void'。在大多数机器上,你会忽略显式的演员。但是,char *对于给定内存位置的地址的位表示与同一内存位置的“ 其他指针 ”地址不同的机器而言,这一点很重要。这将是一个字,而不是字节寻址的机器。这些机器目前并不常见(可能无法使用),但我在大学毕业后第一台机器就是这样的机器(ICL Perq)。

如果你对实现定义的行为不满意%p,请使用C99 <inttypes.h>uintptr_t而不是:

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

这使你可以微调表示以适应自己。我选择了大写的十六进制数字,这样数字的高度就是一样的,并且在开始时0xA1B2CDEF出现的特征下降也就不会出现0xa1b2cdef在数字上。尽管你的选择范围非常广泛。该(uintptr_t)投是通过明确推荐GCC时,它可以读取在编译时的格式字符串。我认为要求演员是正确的,尽管我确信有些人会忽略警告并在大部分时间逃脱。

Kerrek在评论中问道:

我对标准促销和可变参数有点困惑。所有的指针都被标准提升为void *吗?否则,如果int*是两个字节,并且void*是4个字节,那么从参数读取四个字节显然是错误的,非?

我是C标准说,所有的对象指针必须是相同的大小,所以这样的误解,void *int *不能是不同的尺寸。然而,我认为C99标准的相关部分并不那么强调(虽然我不知道我所说的实际情况是否是真实的实际上是错误的):

§6.2.5类型 ¶26指向void的指针应该具有与指向字符类型的指针相同的表示和对齐要求。39)同样,指针兼容的类型的合格或不合格的文本具有相同的表示和对齐要求。所有指向结构类型的指针应该具有相同的表示和对齐要求。所有指向联合类型的指针应该具有相同的表示和对齐要求。指向其他类型的指针不需要具有相同的表示或对齐要求。 39)相同的表示和对齐要求旨在将可互换性作为参数暗示给函数,函数返回值和联合成员。

(C11在§6.2.5,¶28和脚注48中也完全一样)

因此,所有指向结构的指针必须与其他指针的大小相同,并且必须共享相同的对齐要求,即使指针指向的结构可能具有不同的对齐要求。对于工会也是如此。字符指针和空指针必须具有相同的大小和对齐要求。指向int(含义unsigned intsigned int)变体的指针必须具有彼此相同的大小和对齐要求; 类似的其他类型。但C标准并没有正式说出这一点sizeof(int *) == sizeof(void *)。哦,好吧,让你检查你的假设是很好的。

C标准明确地不要求函数指针与对象指针的大小相同。有必要不要在类DOS系统上打破不同的内存模型。你可以有16位数据指针,但是32位函数指针,反之亦然。这就是为什么C标准没有规定函数指针可以转换为对象指针的原因,反之亦然。

幸运的是(对于以POSIX为目标的程序员),POSIX进入违规行为并确保函数指针和数据指针的大小相同:

§2.12.3 指针类型 所有函数指针类型都应该具有与指向void的类型指针相同的表示形式。函数指针的转换void *不得改变表示。void *由这种转换产生的值可以使用明确的转换转换回原始函数指针类型,而不会丢失信息。 注:ISO C标准不要求这样做,但它是POSIX一致性所必需的。

因此,void *在将指针传递给可变参数函数(如可变参数)时,似乎明确强制转换以强化代码中的最大可靠性printf()。在POSIX系统上,将函数指针转换为虚拟指针进行打印是安全的。在其他系统上,这样做不一定安全,除了void *没有演员角色之外,通过指针也不一定安全。

用户回答回答于

p是打印指针的转换说明符。用这个。

int a = 42;

printf("%p\n", (void *) &a);

请记住,省略p转换是未定义的行为,并且使用转换说明符进行打印是以实现定义的方式完成的。

扫码关注云+社区