您的位置:首页 > 编程语言 > C语言/C++

C++中数据内存分布探索笔记

2014-09-19 21:04 363 查看
今天实验室的小洲洲问了小编一个程序的问题,代码如下:

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的高字节到了程序代码中怎么又变成了低字节了呢?

其实,这里有个地方需要注意,在计算机内存中有两种内存分配方式,一种是高字节的数放在高地址,低字节的数放在低地址,还有一种则是相反,高字节的数放在低地址,低字节的数放在高地址,而小编在进行测试的时候碰到的则是第一种情况。

至此,小编简单完成了对内存数据空间分配的简单探索。

共勉之。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: