原创 C语言数据类型大小和结构体中变量的地址分配方法

2008-8-29 10:10 4028 8 8 分类: 软件与OS

C语言数据类型大小和结构体中变量的地址分配方法


数据类型: char  short   int   long   float   double   (long double)
gcc3.2.2: 1      2      4     4       4       8           12
Visual C++:1      2      4     4       4       8            8

对于数组的大小也比较简单,定义数组int a[10]后,sizeof(a)为所有数组元素大小之和,所以在Visual C++下其值为40,但是有一种特殊情况:
void function  (int array[10])     {         printf(\"%d\\n\",sizeof(array));     }
int main(int argc , char *argv[])
{      
   int array[10];
   function(array);
   return 1;

这里的输出结果是4,因为C语言在数组作为参数的时候传递的只是地址,也就是在function这个函数用到的array只不过是个指针变量,其结果返回是4,因为:在Win32平台上地址为32位即指针变量的大小为4字节。顺便提一下关于main中那两个形式参数的意义,假定此main函数编译后为Test.exe的入口。如果在命令行模式(Windows下为cmd,Linux下的shell)运行时,如果你输入 Test 字符串1 字符串2,那么系统在调用此main函数时就会把3传给argc(调用此程序的参数个数输入了3个,程序名也算作一个参数),把 “Test”“ 字符串1”“字符串2”存入字符指针数组argv中,在main函数中就可以使用这些传入的参数了,这样的例子有很多,比如在命令行下运行copy命令时就会输入 copy sourcefile destinationdirectory。
    共用体变量的所占字节数为最大数据类型成员的大小,例如 union Union { int i,char  ch}; Union test; 则test  的大小为4(int类型的大小)。
    枚举类型变量大小为4字节,本人猜测:编译器为了较好的处理字节对齐问题,将枚举类型变量的大小处理为4,不过至今还没有看到过相关的解释。   
    结构体类型变量的大小问题是一些公司招聘的时候很受青睐的题目。(本人在一次笔试中和在参加一本数据结构书的校对过程中曾碰到这个问题,遂写此文)在谭的书中没有涉及到这个问题,严格的说这是个跟编译器字节对齐关系挺大的问题,网上可以搜到很多类似问题的讨论。为了使CPU对变量的进行快速高效的访问,变量的起始地址应该满足某些特性,即所谓的对齐。关于字节对齐有两个重要的宏,#pragma pack (n)和#pragma pack 第一个宏是强制编译器一般以n的倍数进行地址对齐(还有特殊情况以小于n的字节数进行对齐),第二个宏结束前面设置的对齐方式,恢复到编译器默认的对齐方式。在Visual C++下默认的字节对齐数为8。
     结构体中的变量item在结构体中相对于首地址的偏移量应该是 X 的倍数,X 由如下式子确定:X=min(n,sizeof(item)),举个例子(设n为8):struct Test { char c1; char c2; int i};  如果定义了变量Test  t ,那么在存储 t 的 i 时 X 就应该是min(8,sizeof(int))即为4的倍数,即 i 相对于结构体首地址的偏移量必须是4的倍数,所以 t 的大小就应该为8字节(在c1和c2后填充了两个字节以满足前述条件)。对于struct { char c1; char c2}不会出现填充的的情况,每个成员相对首地址的偏移量也满足是X的倍数(此时X为1),其大小为2字节。      
验证程序:
#include <stdio.h>
main()
{
 struct Test
  {char c1; 
   char c2; 
    int i;
  }; 
 struct Test t;
 t.c1=1;
 t.c2=2;
 t.i=3;
 printf(\"%d %d %d %d\\n\",sizeof(t.c1),sizeof(t.c2),sizeof(t.i),sizeof t);
}
输出:1148
    而对于结构struct {char c1; double d;},默认情况下这种结构体变量占用16字节(在c1后填充了7个字节以满足字节对齐)。如果强制编译器以4字节对齐,即在声明这种结构的变量前面有#pragma pack (4),此时X为4,则此种类型结构体变量占用的内存为12字节。
    再看 struct {char c1; double d; char c2;}; 在默认字节对齐的方式下,输出其大小为24,呵呵,这是因为编译器还有一条规定:结构体变量的大小必须要为X(同上定义)的倍数,如果不满足,就会在最后一个成员后填充最少字节数以满足此条件。 如果定义此结构体前有#pragma pack(4),则输出大小为16。
    还有一种特殊情况,就是空结构体。在Visual C++下其大小为1,即struct{}类型的变量在VC下输出其大小是1,解释就是VC为每个结构体变量分配一个字节的内存,以使该变量有个地址;而在gcc下输出其大小为0,我的理解是既然此结构体一个成员都没有,程序中就不会访问它,因此也不必分配内存,如果编译器碰到有访问此结构体成员的情况就会报错。


最后一种情况,结构体成员中有结构体成员的情况,如 struct test1 {  char c1; int i ;  char c2 ;};        struct test2 { int i; struct test1 t1; char c2; };此时考虑在确定上述的X时会把t1拆散成基本数据类型来处理,而考虑test2结构大小时又会把t1作为一个整体来对待,但此时所谓的整体是把test1中确定的那个最大的X拿出来来确定test2的X。 故默认情况下,结构test2类型变量的大小为:20(test1中最大的X被确定为4,test2中也为4,t1占12个字节,在c2后又填充了3字节,总共20字节)。举个例子: [Page]
    struct  test1  {char c1;        double  d;           char c2;};
    struct test2  { int i;      struct test1 t1;        char c2;};
    默认情况下,结构体test2的大小为40(最大的X被确定为8),强制4字节对齐时大小为24。其实这可以理解为编译器的另一条规则:结构体的大小必须为其最大的那个X的整数倍。

文章评论0条评论)

登录后参与讨论
我要评论
0
8
关闭 站长推荐上一条 /2 下一条