sizeof
sizeof是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。
定义:是C/C++的一个操作符。 过程:字节数的计算在程序编译时进行。
作用:判断数据类型长度符的关键字。 返回值:内存所占字节数,其返回值类型为size_t。
补充:typedef unsigned int size_t;
NSLog(@"%zd %zd %zd", sizeof(short), sizeof(int), sizeof(void(*)));
// 输出 2 4 8
基本数据类型的sizeof
| 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有两种语法形式,如下:
sizeof(type_name); // sizeof(类型);
sizeof object; // sizeof对象;
对象 | 对象类型大小计算
int i;
// sizeof int; 错误用法
NSLog(@"%zd %zd %zd ", sizeof(i), (sizeof i), sizeof(int));
// 打印 4 4 4
sizeof计算对象的大小也是转换成对对象类型的计算,及同种类型的不同对象其sizeof值都是一致的。
函数调用求值
sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用。如下:
char foo() {
return 'a';
}
size_t sizeT = sizeof(foo());
NSLog(@"%zd", sizeT);
// 打印:1
指针变量的sizeof
在64位系统中指针变量的sizeof通常为8;32为为4。
指针变量的sizeof值与指针所指的对象没有任何关系,所有的指针变量所占内存大小相等。
数组的sizeof
数组的sizeof值等于数组所占用的内存字节数
char a1[3] = "abc";
char a3[] = "abc";
int a2[3];
NSLog(@"%zd %zd %zd", sizeof(a1), sizeof(a2), sizeof(a3));
// 打印:3 12 4
# ---------------------------------------------------------
void foo3(char a3[3]) {
int c3=sizeof(a3);
NSLog(@"c3== %d", c3);
// 8
}
void foo4(char a4[]) {
int c4=sizeof(a4);
NSLog(@"c4== %d", c4);
// 8
}
// 根据引用类型,调用函数foo3时,会将实参的地址传递过去,则a3为指针类型(char*),所以c3,c4在64位系统中占用8个字节。
补充说明:
'\0':字符串结束符
1、字符数组并不要求它的最后一个字符为'\0',甚至可以不包含'\0'。
2、系统对字符串常量自动添加一个'\0',如:char a3[] = "abc"
3、对于没有指定长度的字符数组,系统不会在最后自动添加结束符'\0'。如:char str[] = {'a', 'b', 'c', 'd'}
4、对于指定了长度的字符数组(初始化字符个数小于字符数组长度),系统会在最后自动添加结束符'\0',如:char string[4]={'a','b','c'};
结构体的sizeof
struct Struct1 {
int a;
char b;
short c;
double d;
}struct1;
struct Struct2 {
double c;
char b;
int a;
short d;
}struct2;
struct Struct3 {
int a;
char b;
struct Struct1 struct1;
short c;
struct Struct2 struct2;
double d;
}struct3;
NSLog(@"%zd %zd %zd", sizeof(struct1), sizeof(struct2), sizeof(struct3));
// 打印 16 24 64
struct Struct1 s1;
s1.a = 2;
s1.b = 'a';
s1.c = 'c';
s1.d = 2.33;
// 断点
分析:
1、通过lldb命令控制台输出s1内存地址
p &s1 -> (Struct1 *) $0 = 0x000000016b2f9b28
x/4gx 0x000000016b2f9b28 ->
0x16b2f9b28: 0x0063006100000002 0x4002a3d70a3d70a4
0x16b2f9b38: 0x0000000000000001 0x00006000020f00c0
2、显示内存:工具栏 -> Debug -> Debug WorkFlow -> View Memory
3、Address出输入内存地址:0x16b2f9b28,显示如下:
02 00 00 00 | 61 00 63 00 |A4 70 3D 0A D7 A3 02 40
- 02 00 00 00:int类型a对应占用4个字节,不足以00补齐
- 61:char类型b占用1个字节
- 63 00:short类型c占用2个字节,不足以00补齐
- 63 00之前的00,是因为要满足成员相对结构体首地址的偏移量是成员大小的整数倍,及「c」相对于Struct1,偏移6个字节,所以前面补齐一个字节00。
- A4 70 3D 0A D7 A3 02 40:double类型d占用8个字节。
s2的同样流程分析:
A4 70 3D 0A D7 A3 02 40 | 61 00 00 00 02 00 00 00 64 00 00 00 00 00 00 00
字节对齐规则
1、结构体变量的首地址能够被其最宽基本类型成员的大小整除;
2、结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
3、结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后填充上字节。