您的位置:首页 > 其它

详细解析sizeof和结构体对齐

2013-10-25 19:37 330 查看
sizeof 是C语言的一种单目运算符,sizeof操作符以字节数形式给出了其操作数的存储大小。操作数可以是一个表达式或者类型名。

sizeof的使用方法

1.用于数据类型

sizeof使用形式:sizeof(type)

数据类型必须用括号括住。如:sizeof(int)

2.用于变量

sizeof(var_name)或者sizeof var_name

变量名可以不用括号括住。

sizeof操作符的结果是size_t,它在头文件中typedef为unsigned int 类型。该类型保证能容纳实现所建立的最大对象的字节大小。

sizeof的结果

1.如果操作数为char、unsigned char或signed char,其结果为1

ANSI C正式规定字符类型为1字节

2.int 、unsigned int 、short int、unsigned short、long int、unsigned long、float、double、long double类型的sizeof没有具体规定,大小依赖于实现。

3.当操作数为指针时,sizeof一般为4

4.当操作数具有数组类型时,其结果为数组的总字节数

5.联合类型操作数的sizeof是其最大成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数。

6.如果操作数为函数中的数组形参或函数类型的形参,sizeof给出其指针大小

sizeof与其他操作符的关系

sizeof的优先级为2级,比/ 、%等3级运算符优先级高。它可以与其他操作符一起组成表达式。如 i * sizeof(int).

sizeof的主要用途

1.sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。

例如:

void *malloc(size_t size)

size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream)

2.sizeof的另一个主要用途是计算数组中元素的个数

void *memset(void *s,int c,sizeof(s))

结构体对齐:

看下面的结构

struct Mystruct

{

double daa1;

char dda;

int type;

};

对这个结构体求sizeof会等于多少呢?也许你会求:sizeof(Mystrcut) = sizeof(double) + sizeof(char) + sizeof(int) = 8+1+4 = 13

当在VC中运行时,你会发现结果为16,这个结果是怎么出现的呢?

其实,这是VC对变量存储的一个特殊处理。为了提高CPU的存储速度,VC对一些变量的起始地址做了对齐处理。在默认情况下,VC规定各变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。下面列出常用类型的对齐方式(VC6.0)

char :偏移量必须为sizeof(char)即1的倍数

int:偏移量必须为sizeof(int)即4的倍数

float:偏移量必须为sizeof(float)即4的倍数

double:偏移量必须是sizeof(double)即8的倍数

short:偏移量必须是sizeof(short)即2的倍数

各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式对齐位置,空缺的字节VC会自动填充。同时VC为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个变量申请空间后,还会根据需要自动填充空缺的字节。

下面为前面的例子进行解释

struct Mystruct

{

double dda1;

char dda;

int type;

};

为上面的结构体分配空间时,VC根据成员变量出现的顺序和对齐方式,先为第一个成员分配空间,其起始地址和结构体的起始地址相同(刚好偏移量为0刚好为sizeof(double)的倍数,该成员变量占用sizeof(double)8个字节;接下来为第二个成员dda分配空间,这时下一个可以分配的地址对齐结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把dda存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof(char)一个字节;接下来给第三个成员变量分配空间,这时下一个可以分配的地址对与结构体的起始偏移量为9,不是sizeof(int)
= 4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节并没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好为sizeof(int)的倍数,所以把type存放在偏移量为12的地方,该成员变量占用4个字节,这时整个结构体变量已经都分配了空间,总的字节数为8+1+3+4 = 16个字节,刚好为结构的字节边界数sizeof(double)的整数倍,没有空缺的字节需要填充。所以最后总的sizeof(Mystruct)的字节数为16.

如果把前面的例子稍微改改,下面的这个结构体该占多少字节呢?

struct Mystruct

{

char dda;

double dda1;

int type;

};

根据前面的规则,不难分析出该结构体的sizeof(Mystruct)占24个字节

struct Mystruct

{

char dda;//偏移量为0,满足对齐方式,dda占用1个字节

double dda1;//下一个可用的地址偏移量为1,不是sizeof(double)的倍数,需要补足7个字节才能使偏移量变为8,因此VC自动填充7个字节,dda1存放在偏移量为8的地址上,它占用8个字节

int type;//下一个可用的地址偏移量为16,是sizeof(int) = 4 的倍数,满足int 的对齐方式,所以不需要VC自送填充,type存放在偏移量为16的地址上,它占用4个字节。

}//所有成员变量都分配了空间,空间总的大小为1+ 7 + 8 +4 = 20,不是结构体的节边界数8的倍数,所以需要填充4个字节,满足结构体大小为sizeof(double)的倍数。

所以该结构体的大小为24个字节。

sizeof用法总结

A.参数为数据类型或者一般变量。例如sizeof(int)、sizeof(long)等等。不同的操作系统得到的结果不同。

B.参数为数组或者指针。举例说明:

int a[50];//sizeof(a) = 4 * 50 = 200;

int *a = new int[50];//sizeof(a) = 4;a为一个指针,sizeof(a)是求指针的大小,在32为系统中,当然是占4个字节。

C.参数为结构或者类。sizeof应用在类和结构的处理情况是相同的。但有两点需要注意:1

1.结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实际地址无关。

2.没有成员变量的结构或者类的大小为1.因为必须保证结构或者类中的每一个实例都有一个唯一的地址。

Class Test{int a;static double c};//sizeof(Test) = 4

Test *s;//sizeof(s) = 4;s 为一个指针

Class test1{};//sizeof(test1) = 1

D.为其他参数

int funct(char s[5])

{

sizeof(s)//函数的参数在传递的时候系统处理为一个指针,所以sizeof(s)为4

}

sizeof(funct("1234")) = 4//因为func的返回类型为int,所以相当于sizeof(int).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: