1. sizeof 定义
sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。
sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。
使用 sizeof 的语法如下:
sizeof (data type)
其中,data type 是要计算大小的数据类型,包括类、结构、共用体和其他用户自定义数据类型。
2.1 基本数据类型的sizeof
int main(int argc, const char * argv[]) {
printf("bool-> %lu\n", sizeof(bool));
printf("char-> %lu\n", sizeof(char));
printf("short-> %lu\n", sizeof(short));
printf("int-> %lu\n", sizeof(int));
printf("long-> %lu\n", sizeof(long));
printf("long long-> %lu\n", sizeof(long long));
printf("NSInteger-> %lu\n", sizeof(NSInteger));
printf("double-> %lu\n", sizeof(double));
printf("float-> %lu\n", sizeof(float));
}
当上面的代码被编译和执行时,它会产生下列结果,结果会根据使用的机器而不同:
bool-> 1
char-> 1
short-> 2
int-> 4
long-> 8
long long-> 8
NSInteger-> 8
double-> 8
float-> 4
####2.2 结构体的sizeof
结构体的sizeof涉及到字节对齐问题。
参考[结构体内存对齐](#3. 内存对⻬的原则)
struct Struct1 {
double a; // 0-7
char c; // 8
int b; // 12 - 15
short d; // 16 - 17
}s1;
struct Struct2 {
double a; // 0-7
int b; // 8-12
char c; // 13
short d; // 14 - 15
}s2;
struct Struct3 {
double a; // 0 - 7
struct Struct1 s; // 8-15 16 20-23 24-25
}s3;
struct Struct4 {
double a1; // 0 - 7
double a; // 8 - 15
char c; // 16
int b; // 20 - 23
short d; // 24 - 25
}s4;
int main() {
NSLog(@"s1->%lu",sizeof(s1)); // 24
NSLog(@"s2->%lu",sizeof(s2)); // 16
NSLog(@"s3->%lu",sizeof(s3)); // s3->32
NSLog(@"s4->%lu",sizeof(s4)); // s4->32
return 0;
}
2.3 联合体的sizeof
结构体在内存组织上市顺序式的,联合体则是重叠式,各成员共享一段内存;所以整个联合体的sizeof也就是每个成员sizeof的最大值。
union un
{
int a;
float b;
double c;
char d;
}u;
printf("size of union %lu", sizeof(u)); // 8
我们一起看下 isa 的大小
#define __x86_64__ 1
typedef unsigned long uintptr_t;
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
# else
# error unknown architecture for packed isa
# endif
union m_isa_t {
m_isa_t(){ }
m_isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
测试结果
@implementation Test
+ (void)test {
union m_isa_t isa1 = m_isa_t((uintptr_t)[Test class]);
union m_isa_t isa2 = m_isa_t();
isa2.cls = [NSObject class];
printf("size of union isa1 %lu\n", sizeof(isa1));
printf("size of union isa2 %lu\n", sizeof(isa2));
}
@end
// size of union isa1 8
// size of union isa2 8
2.4 指针的sizeof
指针是用来记录另一个对象的地址,所以指针的内存大小当然就等于计算机内部地址总线的宽度。
在32位计算机中,一个指针变量的返回值必定是4。
指针变量的sizeof值与指针所指的对象没有任何关系。
char *b = "helloworld";
char *c[10];
double *d;
int **e;
void (*pf)(void);
printf("size of char * %lu\n", sizeof(b));
printf("size of char *[] %lu\n", sizeof(c));
printf("size of double %lu\n", sizeof(d));
printf("size of int** %lu\n", sizeof(e));
printf("size of function pointer %lu\n", sizeof(pf));
/**
size of char * 8
size of char ** 80 指针数组
size of double 8
size of int** 8
size of function pointer 8
*/
2.5 数组的sizeof
数组的sizeof值等于数组所占用的内存字节数。
- 当字符数组表示字符串时,其sizeof值将’/0’计算进去。
- 当数组为形参时,其sizeof值相当于指针的sizeof值。
char arr[10];
char arr2[] = "abc";
printf("size of arr %lu\n", sizeof(arr)); // size of arr 10
printf("size of arr2 %lu\n", sizeof(arr2)); // size of arr2 4
void func(char a[3])
{
int c = sizeof(a); //c = 4,因为这里a不在是数组类型,而是指针,相当于char *a。
}
void funcN(char b[])
{
int cN = sizeof(b); //cN = 4,理由同上。
}
2.6 函数的sizeof
sizeof也可对一个函数调用求值,其结果是函数返回值类型的大小,函数并不会被调用。
对函数求值的形式:sizeof(函数名(实参表))
- 不可以对返回值类型为空的函数求值。
- 不可以对函数名求值。
- 对有参数的函数,在用sizeof时,须写上实参表。
float FuncP(int a, float b)
{
return a + b;
}
printf("size of function %lu\n", sizeof(FuncP(1,3))); // size of function 4
3. 内存对⻬的原则
-
数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要
从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,
结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存
储。
-
结构体作为成员: 如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b
里有char,int ,double等元素,那b应该从8的整数倍开始存储.)。
-
收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大
成员的整数倍.不足的要补⻬。