先由一道经典例题引入,想必很多学习者都遇到过,
第2114行的打印结果毫无疑问是1 2 3;
第2115行的打印结果为1 0 2;因为一般的编译器都是小端存储模式,即数据的低位存储于内存的
低地址中,数据的高位存储于内存的高地址中。前两个%d分别访问a的低32位和高32位,故打印
1,0;第三个%d访问b的低32位,结果打印2。
程序运行结果:
现在进入正题,讨论%hd和%hhd的打印情况;
按照前面的思路,这里%hd打印2个字节的内容(访问16位),结果应该为:1 0 0;
程序运行结果:
结果还是1 0 2,和%d打印结果一样,似乎访问的仍然是四个字节的空间,现做如下实验来验证这
一假设;
赋值a,让其第1和第33位为1,其余位上全部为0,如果猜想正确,则输出应该为 :1 1 2;
继续换%hhd试验:
由上可知,%d,%hd和%hhd在打印long long类型时,将其内存中的补码分成了连续的“4个字节(32位)的单元”,每次访问四个字节(32);
但是下面的这个情况可能会让你感到迷惑:
按照前面的结论 ,%hd和%hhd每次访问四个字节,那下面的两个结果也应该是:65536 65536 2才对;于是猜想:将打印的数据类型在内存中的补码分成“连续的四个字节(32位)的单元”后,不同之处在于%d 和(%hd和%hhd)读取数据的有效位不同;由上面结果我们猜测,%hd和%hhd只读取两个字节(低16位)的内容。
再次验证:
将两个32位的低16位的最高位赋值1,如果%hd和%hhd读取的有效位为16位,则第16位为符号位,打印出来的数应该位负数;上述程序运行结果的确为负数,所以猜想成立。(实际上补码1000000000000000为short短整型数据的最小值-2^15=-32768在内存中的存储数据)
总结:%d,%hd,%hhd在打印long long类型数据时,将其划分为连续的“四个字节的单元(32位)”,且%d读取整个32位,%hd和%hhd读取低16位;
下面继续讨论打印int,short,char类型数据;
2,3均被打印出来了,证明,此情况下 %hd和%hhd仍是遵循访问“四个字节的单元(32位)”这一结论,且两个-32768说明%hd和%hhd打印时,读取的仍是低16位(最高位为符号位),至此前面的结论没有问题。
下面为打印short和char型数据的情况
打印结果均为1 2 3;那连续访问“四个字节的单元(32位)”还是否成立呢,显然是成立的,实际上此时short类型数据会整型提升为int型数据,高位补符号位。严格一点,现在还需要讨论%hhd打印时读取的有效位问题;
第一个输出结果均为负值,说明%hhd打印short数据时读取的最高位也是16位,因为整型提升补符号位;因此前面的结论仍然成立。
同理,打印char
此情况下时,每次打印都发生整体提升,高位补符号位,结论还是成立。
总结:%d,%hd和%hhd在打印时,将其对应的数据在内存中的补码分成了连续的“4个字节的单元”,大于四个字节的类型进化“切割”,小于四个字节的类型发生整体提升,每次访问四个字节,但是%d读取全部32位,%hd和%hhd读取32位的低16位数据。
浮点数不在本次讨论范围。