Jonathan Lef..
213
最简单的答案,假设您不介意不同平台之间的变幻莫测和格式变化,是标准%p符号.
C99标准(ISO/IEC 9899:1999)在§7.19.6.18中说:
p参数应该是指针void.指针的值以实现定义的方式转换为打印字符序列.
(在C11 - ISO/IEC 9899:2011中 - 信息在§7.21.6.18中.)
在某些平台上,这将包括一个领先,0x而在其他平台上它将不会,并且字母可以是小写或大写,并且C标准甚至没有定义它应该是十六进制输出,虽然我知道没有实施的地方没有.
对于是否应该使用强制转换显式转换指针,我们有一定的争论(void *).它是明确的,通常是好的(所以我这样做),标准说'参数应该是指向void'.在大多数机器上,你可以省略一个明确的演员表.然而,在char *给定存储器位置的地址的位表示与相同存储器位置的" 任何其他指针 "地址不同的机器上,这将是重要的.这将是一个字寻址,而不是字节寻址的机器.这些机器现在并不常见(可能不可用),但我在大学毕业后使用的第一台机器就是其中之一(ICL Perq).
如果你不满意的实现定义%p,然后用C99 和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)类似地,指向兼容类型的合格或非限定版本的指针应具有相同的表示和对齐要求.所有指向结构类型的指针都应具有相同的表示和对齐要求.所有指向union类型的指针都应具有相同的表示和对齐要求.指向其他类型的指针不需要具有相同的表示或对齐要求.
39)相同的表示和对齐要求意味着可互换性作为函数的参数,函数的返回值和联合的成员.
(C11在§6.2.5,28和脚注48一节中完全相同)
因此,所有指向结构的指针必须具有相同的大小,并且必须共享相同的对齐要求,即使指针指向的结构可能具有不同的对齐要求.工会也是如此.字符指针和void指针必须具有相同的大小和对齐要求.对int(意义unsigned int和signed 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指针进行打印是安全的.在其他系统上,这样做并不一定安全,除了void *没有强制转换之外,传递指针也不一定安全.
我对标准促销和可变参数有点困惑.所有指针都被标准升级为`void*`吗?否则,如果`int*`是两个字节,而`void*`是4个字节,那么从参数读取四个字节显然是错误的,非? (3认同)