今天实验室的小洲洲问了小编一个程序的问题,代码如下:
int main(int argc, char* argv[])
{
void *vp;
char a = 'A';
short int n = 97;
vp = &a;
cout << *(char *)vp << " " << *(short int *)vp << endl;
vp = &n;
cout << *(char *)vp << " " << *(short int *)vp << endl;
return 0;
}
输出结果如下:
这里出现的问题就是,他尝试通过两个字节的short int类型的指针vp去读取只有一个字节的char类型的内存空间,这样就导致了vp将自动扩充去读取变量a的邻接内存空间,导致出来的结果并不是预想的65,从内存上可以有如此啊分析:
对于变量a中的字符‘A’,它对应的ASCII值为65,从内存二进制上来看,如下图:
而对于-13247而言,从内存二进制上来看,如下图:
从上面可以看到,65和-13247的低字节,也就是低八位是一样的,而这个地方正式变量a的内存空间。
但是,这样又引出了一个问题,-13247前面的高字节,也就是高八位是哪里来的呢?这里有两个猜想,或者是变量a的内存空间的高地址邻接内存空间,或者是变量a的内存空间的低地址邻接内存空间。为了验证究竟是哪个空间,小编进行了如下的测试:
struct MyShortInt
{
char _high;
char _low;
};
struct MyInt
{
char _highest;
MyShortInt _myShortInt;
char _lowest;
};
int main(int argc, char* argv[])
{
void *vp;
char a = 'A';
short int n = 97;
vp = &a;
MyInt myInt;
memset(&myInt, 0, sizeof(MyInt));
myInt._myShortInt._low = 'A';
vp = &myInt._myShortInt._low;
cout << *(char *)vp << " " << *(short int *)vp << endl;
vp = &n;
cout << *(char *)vp << " " << *(short int *)vp << endl;
return 0;
}
结果如图:
在程序中,小编把myInt全部清空,然后在myInt中的中间两个字节填充了‘A’,这样一来,就相当于把short int的前后一个字节都进行了清空操作,避免了小洲洲出现的读取邻接内存空间随机数值的问题(当然,这里的邻接内存空间不一定是随机值,但至少不是我们的预期值)。我们可以发现,最后出现的值正是我们所期望的。
但是,我们仍然没有解决我们之前的问题,因为‘A’只占用一个字节,而该字节的前后邻接字节都是0,我们无从得知,vp指针最后扩充读取的是邻接的低地址字节还是高地址字节。基于这个思路,我们对程序加以改进:
struct MyShortInt
{
char _high;
char _low;
};
struct MyInt
{
char _highest;
MyShortInt _myShortInt;
char _lowest;
};
int main(int argc, char* argv[])
{
void *vp;
char a = 'A';
short int n = 97;
vp = &a;
MyInt myInt;
memset(&myInt, 0, sizeof(MyInt));
myInt._myShortInt._low = 'A';
<span style="color:#ff0000;"> myInt._myShortInt._high = 1;</span>
vp = &myInt._myShortInt._low;
cout << *(char *)vp << " " << *(short int *)vp << endl;
vp = &n;
cout << *(char *)vp << " " << *(short int *)vp << endl;
return 0;
}
结果如下:
我们发现,我们对myInt中间的两个字节中的高字节(在内存中其实是低地址字节)进行了填充之后,程序运行的结果并没有受影响,表明了,邻接低地址字节并没有参与vp指针的扩中读取,为了验证我们的想法,我们对程序进行了进一步的修改:
struct MyShortInt
{
char _high;
char _low;
};
struct MyInt
{
char _highest;
MyShortInt _myShortInt;
char _lowest;
};
int main(int argc, char* argv[])
{
void *vp;
char a = 'A';
short int n = 97;
vp = &a;
MyInt myInt;
memset(&myInt, 0, sizeof(MyInt));
myInt._myShortInt._low = 'A';
<span style="color:#ff0000;">myInt._lowest = 1;</span>
vp = &myInt._myShortInt._low;
cout << *(char *)vp << " " << *(short int *)vp << endl;
vp = &n;
cout << *(char *)vp << " " << *(short int *)vp << endl;
return 0;
}
运行结果如下:
我们发现,最后的结果发生了变化,而这个变化和我们预期的是一样的,为了进一步验证小编想法的正确性,我们可以从内存进行分析:
从图上,我们可以发现,低字节,也就是低八位的值就是前面看到的65,也就是‘A’,而高八位(这里是高地址字节)正是小编刚才在代码中所设置的1。
通过以上的分析,这里小编还需要补充一个地方,可能细心的你会发现,在进行内存分析的时候,321的高字节到了程序代码中怎么又变成了低字节了呢?
其实,这里有个地方需要注意,在计算机内存中有两种内存分配方式,一种是高字节的数放在高地址,低字节的数放在低地址,还有一种则是相反,高字节的数放在低地址,低字节的数放在高地址,而小编在进行测试的时候碰到的则是第一种情况。
至此,小编简单完成了对内存数据空间分配的简单探索。
共勉之。