遇到的问题

今天遇到了一个很奇怪的问题,当使用malloc分配了一个堆空间后,分别尝试用coutprintf尝试打印该地址,出现了两个地址不一样的情况:

int *pp = (int*)malloc(10*sizeof(int));
*pp = 1234;
cout << pp << '\t' << *pp << endl;
printf("0x%x\t%d\n", pp, *pp);
free(pp);

可以看出两个地址低32位是一致的,出现问题的原因应该是printf显示不全导致的。

C/C++占位符,%x和%p的区别-LMLPHP

后来弄明白了,这是C/C++里占位符之间的区别导致的。

C/C++占位符%x和%p

实际上,上面cout流输出的pp表示的就是实际的地址值,和%p是一个意思,当我们使用%p输出时,结果就是正常的:

printf("%p\t%d\n", pp, *pp);

C/C++占位符,%x和%p的区别-LMLPHP

那么%x输出的时候为什么不对呢?这是因为%x是按照int占位4字节来表示的,在16位和32位系统里,由于地址不超过4字节,所以不会导致%x和%p的输出区别。

但是在64位系统里,%p占位变成了8字节,而%x则还是4字节,所以高位就被截断了。

如果需要正确输出,我们可以指定%llx,这样输出结果就是一致的了:

C/C++占位符,%x和%p的区别-LMLPHP

C/C++占位符总结

格式化占位符(format placeholder),语法是:

%[*parameter*][*flags*][*field width*][.*precision*][*length*]*type*

C/C++占位符,%x和%p的区别-LMLPHP

Parameter可以忽略或者是:

Flags可为0个或多个:

Field Width给出显示数值的最小宽度,典型用于制表输出时填充固定宽度的表目。实际输出字符的个数不足域宽,则根据左对齐或右对齐进行填充。实际输出字符的个数超过域宽并不引起数值截断,而是显示全部。宽度值的前导0被解释为0填充标志,如上述;前导的负值被解释为其绝对值,负号解释为左对齐标志。如果域宽值为*,则由对应的函数参数的值为当前域宽。

Precision通常指明输出的最大长度,依赖于特定的格式化类型。对于d、i、u、x、o的整型数值,是指最小数字位数,不足的位要在左侧补0,如果超过也不截断,缺省值为1。对于a,A,e,E,f,F的浮点数值,是指小数点右边显示的数字位数,必要时四舍五入或补0;缺省值为6。对于g,G的浮点数值,是指有效数字的最大位数;缺省值为6。对于s的字符串类型,是指输出的字节的上限,超出限制的其它字符将被截断。如果域宽为*,则由对应的函数参数的值为当前域宽。如果仅给出了小数点,则域宽为0。

Length指出浮点型参数或整型参数的长度。此项Microsoft称为“Size”。可以忽略,或者是下述:

类型 Type,也称转换说明(conversion specification/specifier),可以是:

参考文献

1:C语言中的%p和%x的区别_百度知道

2:格式化字符串 - 维基百科,自由的百科全书

如有疑问或错误,欢迎和我私信交流指正。
版权所有,未经授权,请勿转载!
Copyright © 2023 by Mr.Idleman. All rights reserved.

04-23 21:07