概述
对于C语言开发人员来说,sizeof应该不陌生吧。此次我主要写的是sizeof对各变量长度的计算方式。
sizeof这个函数主要是对各数据类型的长度进行计算,入参为数据类型,返回值计算结果。但由于不同OS的系统架构下,sizeof计算的结果会存在一定的差异。下文主要基于32位系统,讨论sizeof的计算方式。
比较常见的场景是基本数据类型长度的计算结果如下:
类型
|
32位系统(bytes)
|
64位系统(bytes)
|
bool
|
1
|
1
|
char
|
1
|
1
|
short
|
2
|
2
|
int
|
4
|
4
|
long
|
4
|
8
|
long long
|
8
|
8
|
char *
|
4
|
8
|
float
|
4
|
4
|
double
|
8
|
8
|
long double
|
12
|
16
|
说明:char*代表指针变量,不管什么类型的指针,指针变量长度都是一样的。
为了加快CPU取数速度,C标准规定
变量存放地址一定为自身长度的整数倍。因此变量间就会出现缝隙空间,这时编译器在编译期间就会对这些缝隙进行填充,叫做变量的对齐与补齐规则。接下来我会举例说明各种场景下的对齐与补齐方式:
例1:
#include <stdio.h>
struct st
{
char a;
int b;
short c;
long d;
};
int main(void)
{
struct st tmp;
printf("&tmp.a=%pn",&(tmp.a));
printf("&tmp.b=%pn",&(tmp.b));
printf("&tmp.c=%pn",&(tmp.c));
printf("&tmp.d=%pn",&(tmp.d));
printf("sizeof(tmp)=%dn",sizeof(tmp));
return 0;
}
执行结果:
&tmp=0xbfe6e960
&tmp.a=0xbfe6e960
&tmp.b=0xbfe6e964
&tmp.c=0xbfe6e968
&tmp.d=0xbfe6e96c
sizeof(tmp)=16
从结果可以出成员变量的存放地址都是自身长度的整数倍。但结构体有所不同,结构体变量的地址应该为其最大成员变量长度的整数倍,且各成员变量遵守对齐与补齐规则,包括最后一个成员变量。所以 st结构体的大小为:1(a)+3(填充)+4(b)+2(c)+2(填充)+4(d)=16
例2:
struct st
{
char a;
int b;
short c;
long d;
static int e;
};
结果:
sizeof(tmp)=16
在C++中可能会见到结构体中定义静态成员的代码,由于静态成员在定义时就已经分配的内存空间,所以用sizeof来计算结构体大小时,是不计算在内的。
例3:
struct st1
{
}tmp1;
结果:
sizeof(st1)=0
空结构体的大小为0,该类型不占用任何的地址空间。
例3:
void fun(void)
{
}
printf("sizeof(void)=%dn",sizeof(void));
printf("sizeof(fun)=%dn",sizeof(fun));
printf("sizeof(fun())=%dn",sizeof(fun()));
结果:
sizeof(void)=1
sizeof(fun)=1
sizeof(fun())=1
void类型的大小为1,sizeof也可以用来计算函数的大小以及返回值。
从执行文件的头部信息来看:
Num: Value Size Type Bind Vis Ndx Name
48: 080483c4 5 FUNC GLOBAL DEFAULT 13 fun
函数fun应该是占用5个字节的,这里不知道为什么打印出来只有1个字节?不过一般不会用sizeof来计算函数大小,没有什么意义。
例4:
struct st2
{
char a:1;
char b:4;
char c:5;
short d:10;
};
结果:
sizeof(st2)=4
这个例子结合位变量来说明字节对齐与补齐的规则,结构体中各成员变量存放如下:
|0|1234|567 01234567 01234567 01234567| //4个字节长度
|a| b | | c | | d | //4个变量存放
首先a占用了第一个字节的最低位,b占用了第1到第4位,由于c所占的位数超过了上一字节空闲的位数,所以c从下一字节的地址开始算起,占用第0到第4位。变量d由于是short型变量,需要以2字节对齐,所以地址从第3个字节的低位开始算,长度为10,余下6个位自动补齐。最终,该结构体大小为4字节。
例5:
union st2
{
char a;
shot b;
int c;
};
结果:
sizeof(union)=4
联合体中成员是共享内存的,所以长度为最大成员变量的大小。
例6:
struct st
{
char a;
int b;
short c;
long d;
//最大长度为4
};
struct st2
{
char a;
short d;
//最大长度为2
char e;
};
struct st4
{
struct st a;
//16个字节
struct st2 b;
//6个字节
};
结果:
sizeof(st4)=24
在st4结构体中,成员a占用16个字节,成员b占用6个字节,为什么 最终st4会占用24个字节呢?原因是a中变量最大长度为4,所以a以4字节对齐,b中变量最大长度为2,所以b以2字节对齐,但对于st4结构体来说,它内部基本数据类型最长为4字节,所以st4结构体以4字节对齐,最后会在后面填充2个字节。
总之,sizeof计算规则如下:
1、基本数据类型变量地址为自身长度的整数倍
2、对于结构体,sizeof会把编译器自动填充的字节算在内。
3、sizeof不计算静态变量的长度
C语言提供了#pragma宏可以指定字节对齐的长度:
例7:
#include <stdio.h>
#pragma pack(2)
//强制以2字节对齐
struct st
{
char a;
int b;
};
void main(void)
{
printf("sizeof(struct st)=%dn",sizeof(struct st));
}
结果:
sizeof(struct st)=6
st结构体中成员b的初始地址不再是4的位数,而是2的倍数。
最后
以上就是伶俐哈密瓜为你收集整理的C语言sizeof的计算方式的全部内容,希望文章能够帮你解决C语言sizeof的计算方式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复