3.sizeof
sizeof是C/C++中的一种单目操作符,不是函数。
作用就是返回一个对象或者类型所占的内存字节数。返回值类型为siz_t.
1.用于类型 sizeof(type) 数据类型必须用括号括住 例如sizeof(int)。
2.用于变量或对象 sizeof(object)或者sizeof object 推荐使用括号形式,保持统一也为了防止错误
3.sizeof操作符不能用于函数类型,不完全类型或者位字段。
不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。
sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。
例如: int fun(int a,int b){} sizeof(fun(3,4)); 相当于sizeof(int);
例如: int max(int a,int b){} sizeof(max); 错误
int a[MAX]; MAX大小未知 sizeof(a); 错误 sizeof(void) ; 错误
sizeof操作符的结果类型是size_t,它在头文件中typedef为 unsigned int类型。 保证能容纳实现所建立的最大对象的字节大小。
1、类型char、unsigned char或signed char在所有平台下,其sizeof的结果都为1。
32位机linux平台下 64位机linux平台下
int 4 4
unsigned int 4 4
short int 2 2
long int 4 4
unsigned long 4 8
float 4 8
double 8 8
long double 12 12
2. sizeof的常量性
sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用。C99标准规定sizeof也可以在运行时刻进行计算
3. 指针变量的sizeof
指针变量的sizeof值与指针所指的对象没有任何关系
int *p1; char *p2 = "hello"; string* p3; char** p4 = &p2;
sizeof(p1) == sizeof(p2) == sizeof(p3) ==sizeof(p4); 32位系统下为4,64位系统下为8
4. 数组的sizeof
char a1[]="hello";
int a2[100]; sizeof(a1) = 6; sizeof(a2) = 400;
数组传参时,是传址方式,传的是数组的地址
操作数是函数中的数组形参或函数指针类型的形参,sizeof给出其指针的大小。
5. 联合体类型(union)的sizeof是其最大字节成员的字节数。
因为结构体在内存组织上是顺序式的,而联合体则是重叠式,各成员共享一段内存
例 union a{ int a; char b; double c; }; sizeof(a) = 8;
6.结构体类型的sizeof要注意字节对齐
字节对齐的原因是:计算机组成原理告诉我们字节对齐有助于加快计算机的取数速度,否则就得多花指令周期了
三个准则: 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍, 如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
struct S2{
int i;
char c;
};
结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
例如,想要获得S2中c的偏移量,方法为
size_t pos = offsetof(S2, c);// pos等于4
关于三个对齐规则参考博客: https://blog.csdn.net/u013057233/article/details/76573347
7. “空结构体”(不含数据成员)的大小不为0,而是1。
试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢
于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。
8.含位域结构体的sizeof
位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof。C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字
段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字
段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方
式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
例子: struct a1{
char f1:3;
char f2:4;
char f3:5;
}; 3+4+5>8 所以 sizeof(a1) = 2;
struct a2{
char f1:3;
int f2:4;
char f3:5;
} ;相邻位域类型不同, sizeof(a2) = 1+4+1; VC++
struct a3
{char f1:3;
int f2;
char f3:5;
};非位域字段穿插在其中,不会产生压缩,在VC和Dev-C++中得到的大小均为3。
9.sizeof测类所占字节的大小
1.空类,使用sizeof求得其大小为1。
2.类里面的静态成员变量不计算,因为sizeof只能测堆栈区的数据字节数,无法测数据区的字节数
3.带虚函数的类
虚函数放在虚表中,类中定义了虚函数,需要存放一个指向虚表的指针。
当有多个虚函数时,仍然只有一个指向虚表的指针
更多参考博客: https://blog.csdn.net/szchtx/article/details/10254007