C语言中%u与%d格式说明符的区别及地址打印差异问题
复现代码
#include<stdio.h> int main(){ int a = 3; printf("%u\n",&a); printf("%d\n",&a); return 0; }
%u与%d的核心区别
两个格式符的解析规则完全不同,对应的数据类型也不一样:
%d:将传入参数按有符号int类型解析为十进制整数,遵循二进制补码规则,最高位为符号位,取值范围包含负数。%u:将传入参数按无符号unsigned int类型解析为十进制整数,所有二进制位都用于表示数值,不存在符号位,取值范围从0开始,没有负数。
打印同一地址得到不同输出的原因
首先需要明确:用%d或%u打印内存地址本身就属于C标准定义的未定义行为,二者从设计上就不是用来处理指针类型参数的,输出异常是必然结果。具体数值差异的来源有两个:
- 解析规则差异
内存地址是无符号的整数值,如果地址值被截断为int长度后,最高二进制位为1:用%d解析时会把最高位识别为符号位,最终输出一个负整数;用%u解析时最高位会被当作普通数值位,最终输出一个值很大的正整数。二者是同一段二进制数据按不同规则翻译得到的结果,和地址本身是否变化没有关系。
举个实际例子:如果截断后的地址二进制对应32位十六进制值0xBFFFF123:- 按
%d(有符号int)解析得到十进制值-1073745629 - 按
%u(无符号int)解析得到十进制值3221221667
- 按
- 长度不匹配导致截断
目前主流64位环境下,指针类型长度为8字节,而int类型长度固定为4字节。用%d/%u打印指针时,printf只会从栈上读取4字节的内容,直接把高4位的地址数据截断,最终输出的值本身就不是完整的内存地址,结果自然不可靠。
打印内存地址的标准写法是使用
%p格式符,同时将指针强转为void*类型,示例:printf("%p\n", (void*)&a);
内容的提问来源于stack exchange,提问作者RACHIT MITTAL
相关产品推荐
相关产品推荐

