题目源自第一次去华为面试的时候一面面试官出的代码。
int val = 0x123456789;
char* prt =(char*) &val;
printf("%x\n",prt[0]);
运行结果如下图:
目前为止自己的分析如下~
1.对于0x123456789来说,由于十六进制的每1位对应于二进制的4位,则每2位对应1个字节,int数据类型大小为23456789转换为二进制已经有8个字节,最高位的1被舍弃。
2.因此val为 0010 0011 0100 0101 0110 0111 1000 1001.
3.prt为指向char类型的指针,char类型大小为1个字节,因此对指针来说,+1就等于地址往后跳1个字节。(若数据类型为int,则+1等于地址往后跳4个字节)
4.首先不考虑为什么输出的是89这两位,考虑为什么输出为ffffff89,将代码稍加修改为
int val = 0x123456789;
char* prt =(char*) &val;
printf("%x\n",prt[0]);
printf("%x\n",prt[1]);
printf("%x\n",prt[2]);
printf("%x\n",prt[3]);
printf("%x\n",*(prt+3));
运行结果如下图:
可见其余前几位输出均与原来相等。
考虑到prt所指地址存的数据为 1000 1001,当将这个数据作为一个十六进制输出时,数据类型为int为有符号类型,则首位的1将会看做符号位,将1000 1001按位取反加1,得到 0111 0111,对应的十进制为119,加上符号位则为-119,将-119重新写为int类型则为 1111 1111 1000 1001,按十六进制输出则为 ffffff89。
5.搞清楚为什么输出会变成ffffff89后,考虑为什么prt指向的地址所存数据为89而不是23。由于这里的val存放在栈区,个人猜测可能与栈内存的生长方向有关。
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意
思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有
的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将
提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储
的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小
受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
假设val存在地址 0001~0004中,则存储方式如下:
0001:1000 1001
0002:0110 0111
0003: 0100 0101
0004: 0010 0011
当prt所指类型为char,指针为从栈顶向下1个字节,为0001。
以上为个人想法,不保证正确性,留待以后随时修改。