今天网上看到这么一个问题:
int array[
5]
= {};
sizeof(array)=?int Fuction(int a[])
{
return sizeof(a);
}
Fuction(array)=?
很有意思的问题,大概很多人会认为结果是20、20,但其实正确的答案是20、4,也就是说,函数Fuction里的sizeof求值结果为4,这应该就是int*的字节大小,看起来sizeof求的是数组a[]的首指针字节大小。奇怪的地方也就是这里,一个在函数外面,一个在函数内部,sizeof的参数完全一样啊,为什么结果却完全不同呢?
这里大家对sizeof的用法大致了解,其实出现这个结果的原因不在sizeof,当sizeof传入的参数是数组时,其结果的确是该数组占内存的大小,不过,c++中函数有一个特性:
数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。
也就是说,在int Fuction(int a[])中,编译器认为传入的参数不是数组,而是把数组a[]的首地址指针传进去,所以这时sizeof(a)求的是指针而不是数组的大小。
至于为什么编译器为什么会这样,我想大概是考虑到栈空间的限制吧。C++里函数的参数由栈空间保存,而这个栈空间的大小一般都是受限的,比较小,所以可能会出现栈空间耗尽导致函数无法调用的情况,为了防止这种情况的发生,就需要做一些优化,所以才会将传入的数组参数的首指针进栈,这样可以节约很多的栈空间。
另外想到以前面试时碰到的一个问题,也是跟sizeof有关。
struct MEM
{
int a;
char b;
float c;
}test;
sizeof(test) = ?
这个问题考察的其实不再是sizeof的用法了,而是字节对齐的知识:在计算类似结构和类变量的大小就必须考虑字节对齐问题。为了CPU存取的速度最快,C++在处理数据时经常把结构变量中的成员的大小按照4或8的整数倍的地址存储,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。
比如在上面的例子中,如果把test的起始地址认为是0,那么test.a的起始地址为0,test.b的起始地址为0 + sizeof(int) = 4,然后test.c的地址呢?注意,test.c的起始地址不是0 + sizeof(int) + sizeof(char) = 5,而应该是0 + sizeof(int) + sizeof(float) = 8,在这里,C++为了存取效率的考虑,将char后面的3个字节空出来,这都是为了而将test.c的起始地址放在4的整数倍的位置,这样是为了更方便这个float数据的存取。因为32位CPU存取数据都是按照4个字节来操作,也就是说一次性的读出或者写入4字节(也就是32bit)的数据是最快的,所以将数据字节对齐后,虽然浪费了一些内存,但是存取数据却更快了。
我们来分析一下,在这里如果没有字节对齐的话,CPU如何取出float呢?这就要分三步来了:首先,取出偏移地址为4的4字节数据(这四字节里第一个字节是char,后面三个是float的),然后在便宜地址为8的地方取4个字节(这四个字节里第一个字节是float的),最后再把两部分(前面的3字节和后面的1字节)组合起来,这样需要两次读操作和一次组合。但是字节对齐后,只需要一步读操作(即在偏移地址为8的地方取4个字节),效率显然提高很多。
阅读(1007) | 评论(0) | 转发(0) |