设为首页 加入收藏

TOP

6.3 sizeof(1)
2013-10-07 14:09:24 来源: 作者: 【 】 浏览:60
Tags:6.3 sizeof

6.3  sizeof(1)

面试例题1:What is the output of the following code (下面代码的输出结果是什么?)[美国某著名计算机软硬件公司2005年、2007年面试题]

  1. #include <iostream> 
  2. #include <stdio.h> 
  3. #include <string.h> 
  4. using namespace std;  
  5. struct{  
  6. short a1;  
  7. short a2;  
  8. short a3;  
  9. }A;  
  10. struct{  
  11. long a1;  
  12. short a2;  
  13. }B;  
  14.  
  15.  int main()  
  16.   {  
  17.       char* ss1 = "0123456789";  
  18.       char ss2[] = "0123456789";  
  19.       char ss3[100] = "0123456789";  
  20.       int  ss4[100] ;  
  21.       char q1[]="abc";  
  22.       char q2[]="a\n";  
  23.       char* q3="a\n";  
  24.       char *str1 = (char *)malloc(100);  
  25.  
  26.       void *str2 = (void *) malloc(100);  
  27.  
  28.       cout << sizeof(ss1) << "  ";  
  29.       cout << sizeof(ss2) << "  ";  
  30.       cout << sizeof(ss3) << "  ";  
  31.       cout << sizeof(ss4) << "  ";  
  32.       cout << sizeof(q1) << "  ";  
  33.       cout << sizeof(q2) << "  ";  
  34.       cout << sizeof(q3) << "  ";  
  35.       cout << sizeof(A) << "  ";  
  36.       cout << sizeof(B) << "  ";  
  37.       cout << sizeof(str1) << "  ";  
  38.       cout << sizeof(str2) << "  ";  
  39.  
  40.       return 0;  
  41.   } 

解析:

ss1是一个字符指针,指针的大小是一个定值,就是4字节,所以sizeof(ss1)是4字节。

ss2是一个字符数组,这个数组最初未定大小,由具体填充值来定。填充值是"0123456789"。1个字符所占空间是1字节,10个就是10字节,再加上隐含的"\0",所以一共是11字节。

ss3也是一个字符数组,这个数组开始预分配100,所以它的大小一共是100字节。

ss4也是一个整型数组,这个数组开始预分配100,但每个整型变量所占空间是4,所以它的大小一共是400字节。

q1与ss2类似,所以是4字节。

q2里面有一个"\n","\n"算做一位,所以它的空间大小是3字节。

q3是一个字符指针,指针的大小是一个定值,就是4,所以sizeof(q3)是4字节。

A和B是两个结构体。在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素的长度都小于处理器的位数的时候,便以结构体里面最长的数据元素为对齐单位,也就是说,结构体的长度一定是最长的数据元素的整数倍。如果结构体内存在长度大于处理器位数的元素,那么就以处理器的位数为对齐单位。但是结构体内类型相同的连续元素将在连续的空间内,和数组一样。

结构体A中有3个short类型变量,各自以2字节对齐,结构体对齐参数按默认的8字节对齐,则a1、a2、a3都取2字节对齐,sizeof(A)为6,其也是2的整数倍。B中a1为4字节对齐,a2为2字节对齐,结构体默认对齐参数为8,则a1取4字节对齐,a2取2字节对齐;结构体大小为6字节,6不为4的整数倍,补空字节,增到8时,符合所有条件,则sizeof(B)为8。

CPU的优化规则大致原则是这样的:对于n字节的元素(n=2,4,8,…),它的首地址能被n整除,才能获得最好的性能。设计编译器的时候可以遵循这个原则:对于每一个变量,可以从当前位置向后找到第一个满足这个条件的地址作为首地址。例子比较特殊,因为即便采用这个原则,得到的结果也应该为6字节(long的首地址偏移量0000,short首地址偏移量0004,都符合要求)。但是结构体一般会面临数组分配的问题。编译器为了优化这种情况,干脆把它的大小设为8字节,这样就没有麻烦了,否则的话,会出现单个结构体的大小为6字节,而大小为n的结构体数组大小却为8×(n-1)+6的尴尬局面。IBM出这道题并不是考查理解语言本身和编译器,而是考查应聘者对计算机底层机制的理解和设计程序的原则。也就是说,如果让你设计编译器,你将怎样解决内存对齐的问题。

答案:

4,11,100,400,4,3,4,6,8,4,4。

扩展知识(内存中的数据对齐)

数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽。x86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据时,会在内部进行一系列的调整。这些调整对于程序来说是透明的,但是会降低运行速度,所以编译器在编译程序时会尽量保证数据对齐。同样一段代码,我们来看看用VC、Dev C++(www.cppentry.com)和LCC这3个不同的编译器编译出来的程序的执行结果:

  1. #include <stdio.h> 
  2.  
  3. int main()  
  4. {  
  5. int a;  
  6. char b;  
  7. int c;  
  8. printf("0x%08x ",&a);  
  9. printf("0x%08x ",&b);  
  10. printf("0x%08x ",&c);  
  11. return 0;  

这是用VC编译后的执行结果:

  1. 0x0012ff7c  
  2. 0x0012ff7b  
  3. 0x0012ff80 

变量在内存中的顺序:b(1字节)-a(4字节)-c(4字节)。

这是用Dev C++(www.cppentry.com)编译后的执行结果:

  1. 0x0022ff7c  
  2. 0x0022ff7b  
  3. 0x0022ff74 

变量在内存中的顺序:c(4字节)-中间相隔3字节-b(占1字节)-a(4字节)。

这是用LCC编译后的执行结果:

  1. 0x0012ff6c  
  2. 0x0012ff6b  
  3. 0x0012ff64 

变量在内存中的顺序:同上。

3个编译器都做到了数据对齐,但是后两个编译器显然没VC"聪明",让一个char占了4字节,浪费内存。

面试例题2:以下代码为32位机器编译,数据是以4字节为对齐单位,这两个类的输出结果为什么不同?[中国著名软件企业JS公司2008年4月面试题]

  1. class   B  
  2. {  
  3. private:  
  4. bool   m_bTemp;  
  5. int   m_nTemp;  
  6. bool   m_bTemp2;  
  7. };  
  8.  
  9. class   C  
  10.  
  11.  
  12. {  
  13.  
  14.  
  15. private:  
  16. int   m_nTemp;  
  17. bool   m_bTemp;  
  18. bool   m_bTemp2;  
  19. };  
  20.  
  21.  
  22. cout   <<   sizeof(B)   <<   endl;  
  23. cout   <<   sizeof(C)   <<   endl

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇老程序员10年技术生涯的思考 从C+.. 下一篇6.2 const

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: