c - 正确的格式说明符以打印指针或地址?

标签 c pointers format memory-address

我应该使用哪种格式说明符来打印变量的地址?我对以下很多东西感到困惑。


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


哪种是打印地址的最佳格式?

最佳答案

假设您不介意不同平台之间格式的变化和变化,最简单的答案是标准%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那样沿数字上下倾角。不过,您可以在非常广泛的范围内进行选择。当GCC可以在编译时读取格式字符串时,明确建议使用(uintptr_t)强制转换。我认为请求演员表是正确的,尽管我敢肯定有些人会忽略警告并在大多数情况下逃避它。



Kerrek在评论中要求:


  我对标准的促销活动和各种各样的争论感到困惑。所有指针是否都标准提升为void *?否则,如果int*是两个字节,而void*是4个字节,那么从参数中读取四个字节显然是错误的,不是吗?


我对C标准说所有对象指针必须具有相同的大小感到幻想,因此void *int *不能具有不同的大小。但是,我认为C99标准的相关部分并没有那么强调(尽管我不知道我建议为true的实现实际上是false的实现):


  §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.3Pointer Types
  
  所有功能指针类型都应与void的类型指针具有相同的表示形式。将函数指针转换为void *不得更改表示形式。可以使用显式强制转换将这种转换产生的void *值转换回原始函数指针类型,而不会丢失信息。
  
  注意:
  ISO C标准不需要这样做,但是为了符合POSIX要求,它是必需的。


因此,当将指针传递给可变参数函数(例如void *)时,为确保代码的最大可靠性,强烈建议显式转换为printf()。在POSIX系统上,将函数指针强制转换为空指针以进行打印是安全的。在其他系统上,这样做不一定是安全的,传递void *以外的指针而不进行强制转换也不一定安全。

关于c - 正确的格式说明符以打印指针或地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58578551/

相关文章:

c - 在标准 C 中分割字符串而不使用 strtok() 和 strsep()?

iphone - 如何使用 scanf 接受 NSString 中的值?

我可以释放最初从另一个指针分配的内存吗?

c# - 将日期时间从数据表转换为特定格式的字符串 C# ASP.NET

python - 处理具有几乎相似记录但时间不同的 csv 文件 - 需要将它们分组为一条记录

c - c中文件打开模式的区别

c - sqrt 函数出现小错误

c++ - 调试 C++ 代码

c++ - 在 C++ 中声明指向对象的指针实际上意味着什么?

java - 17 :42:55. 7385459 如何在java中制作这个日期格式