结构体(struct
)或者联合体(union
)的数据成员,第一个数据成员放在offset为0的地方,之后每一个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,好比说是数组,结构体等)的整数倍开始(好比int
为4字节,则要从4的整数倍地址开始存储)。express
若是一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储)。数组
结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍。不足的要补齐。markdown
C | OC | 32位 | 64位 |
---|---|---|---|
bool | BOOL(64位) | 1 | 1 |
signed char | (__signed char)int8_t、BOOL(32位) | 1 | 1 |
unsigned char | Boolean | 1 | 1 |
short | int16_t | 2 | 2 |
unsigned short | unichar | 2 | 2 |
int 、int32_t | NSInteger(32位)、boolean_t(32位) | 4 | 4 |
unsigned int | boolean_t(64位)、NSUInteger(32位) | 4 | 4 |
long | NSInteger(64位) | 4 | 8 |
unsigned long | NSUInteger(64位) | 4 | 8 |
long long | int64_t | 8 | 8 |
float | CGFloat(32位) | 4 | 4 |
double | CGFloat(64位) | 8 | 8 |
sizeof()
是C/C++
中的关键字,它是一个运算符,不是函数。做用是取得一个对象(数据类型或者数据对象)的长度(即占用内存的大小,以byte
为单位,返回size_t
)。基本数据类型(int
、double
等)的大小与系统相关。结构体涉及字节对齐。函数
示例:post
struct Stu {
char c;
int i;
double d;
};
void test() {
//基本数据类型
int age = 18;
size_t sizeAge1 = sizeof(age);
size_t sizeAge2 = sizeof age;
size_t sizeAge3 = sizeof(int);
NSLog(@"age size: %zu, %zu, %zu",sizeAge1,sizeAge2,sizeAge3);
//结构体
struct Stu s;
s.c = 'c';
s.i = 18;
s.d = 180.0;
size_t sizeS1 = sizeof(s);
size_t sizeS2 = sizeof s;
size_t sizeS3 = sizeof(struct Stu);
NSLog(@"s size: %zu, %zu, %zu",sizeS1,sizeS2,sizeS3);
//指针
NSObject *obj = [NSObject alloc];
size_t sizeObj1 = sizeof(obj);
size_t sizeObj2 = sizeof obj;
size_t sizeObj3 = sizeof(NSObject *);
NSLog(@"obj size: %zu, %zu, %zu",sizeObj1,sizeObj2,sizeObj3);
}
复制代码
输出:spa
age size: 4, 4, 4
s size: 16, 16, 16
obj size: 8, 8, 8
复制代码
sizeof
是运算符不是函数。3种语法形式均可以,须要注意的是经过类型获取的方式必须在()
中。这个函数是rutime
提供的获取类的实例锁占用的内存大小。大小至于成员变量有关。获取的是实际占用的空间(8字节对齐
)。指针
malloc_size
就是alloc
中实际开辟的空间。code
Struct1
和Struct2
分别占用多大内存?struct Struct1 {
double a; // [0,7]
char b; // [8]
int c; // 根据第一准则要从4的倍数开始,因此[12,13,14,15]。跳过9,10,11
short d; //[16,17]
}struct1;
//根据第三准则总大小要是8的倍数,那就要分配24字节。
struct Struct2 {
double a; //[0,7]
int b; //[8,11]
char c; //[12]
short d; //根据准则1跳过13,从14开始 [14,15]
}struct2;
//这里0~15大小原本就为16了,因此不须要补齐了。
复制代码
验证:orm
NSLog(@"struct1 size :%zu\nstruct2 size:%zu",sizeof(struct1),sizeof(struct2));
复制代码
输出:对象
struct1 size :24
struct2 size:16
复制代码
0
开始,Struct2
并无进行第三原则补齐。Struct3
中有结构体嵌套,那么占用大小是多少?struct Struct3 {
double a; //[0,7]
int b; //[8,11]
char c; //[12]
short d; //跳过13 [14,15]
int e; // [16,19]
struct Struct1 str; //根据准则2,Struct1最大元素为`double`类型,因此从24开始。根据`Struct1`分配的时候24个字节,因此str为[24,47]
}struct3;
//因此Struct3占用内存大小为48字节。
复制代码
验证:
NSLog(@"struct3 size :%zu",sizeof(struct3));
struct3 size :48
复制代码
在这里有个疑问,准则3
是先做用在Struct1
再做用Struct3
仍是最后直接做用在Struct3
?不妨验证一下:
struct Struct4 {
struct Struct1 str;
char c;
}struct4;
复制代码
Struct1
自己占用18字节
,补齐后占用24字节
。若是Struct4
最终占用32字节那么就是第一种状况,张永24 字节则是第二种状况。
NSLog(@"struct4 size :%zu",sizeof(struct4));
struct4 size :32
复制代码
这也就验证了猜测,结构体嵌套从内部开始补齐。这也符合常理。
struct S1 {
int a; // 4 [0,3]
char b;// 1 [4]
short c; // 2 [6,7]
}; // 0~7 8字节
struct S2 {
double a; // 8 [0,7]
char b; // 1 [8]
struct S1 s1; // 8 [12,19] 按s1自身中存的最大a的4字节的倍数对齐
bool c; // 1 [20]
};
//0~20一共21个字节,按最大的8字节对齐。应该24字节。
复制代码
struct S2 s2;
NSLog(@"size :%zu",sizeof(s2));
复制代码
这个时候s2
大小为多少?
分析:
S1:
int a
占4
个字节,从[0~3]
。char b
占1
个字节,[4]
。short c
占2
个字节,须要以2
字节对齐,因此跳过5
[6~7]
S1
总体从0~7
不须要补齐。占8
字节。S2:
double a
占8
字节,[0~7]
。char b
占1
字节,[8]
。struct S1 s1
占8
字节。因为S1
内部最大元素为int a
因此须要4
倍对齐,因此[12~19]
。bool c
占1
字节,[20]
。S2
总体从0~21
一共21
字节,须要按S2
中最大元素double a
补齐。因此应该是24
字节。输出:
size :24
复制代码