iOS 结构体struct、联合体union内存大小分析

1,065 阅读4分钟

结构体

结构体是把不同类型的数据组合成一个整体,其元素是共存的,元素是否使用都会分配内存。
优点 : 元素之间存储互不影响,容量大,“有容乃大”。
缺点 : 结构体的内存 >= 所有元素所占内存之和,比较浪费内存。

举个例子:

struct LGStruct1 {
    double a;     
    char b;      
    int c;       
    short d;     
}struct1;

struct LGStruct2 {
    double a;      
    int b;         
    char c;        
    short d;       
}struct2;

结构体大家都熟悉,但是结构体大小怎么计算未必都清楚,现提供提供计算秘诀

1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要
从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,
结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存
储。 min(当前开始的位置m n) m = 9 n = 4  9 10 11 12

2:结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从
其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b
⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)

3:收尾⼯作:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤
成员的整数倍.不⾜的要补⻬。

跟着这个公式我们来计算下大小

struct LGStruct1 {     字节数      存储位置
    double a;    //      8          [0, 7]
    char b;      //      1          [8]
    int c;       //      4      9,10,11,[12,13,14,15]
    short d;     //      2         [16, 17]
}struct1;

分析:

a 占8个字节,从0 开始,a占的位置就是0-7;

b 占1个字节,根据公式1,8是1的整数倍,所以8这个位置可以存放,

c 占4个字节,根据公式1,9不是4的整数倍,所以往后排,10,11 都不是,12是4的整数倍,所以从12开始,12,13,14,15

d 占2个字节,工具公式1,16是2的整数倍,所以从16开始,16,17

根据公式3,struct1中最大的是a,17不是8的整数倍,要往后补齐,到24的时候是8的整数倍,所以struct1 的大小是24;

接下来我们打印验证

image.png 打印的结果和我们计算的完全一样。用同样的方法计算下一个

struct LGStruct2 {
    double a;       // 8    [0 7]
    int b;          // 4    [8 9 10 11]
    char c;         // 1    [12]
    short d;        // 2    (13 [14 15] 
}struct2;

大小为16

image.png 可以看出struct1和struct2中元素一样,只是位置不同则结构体的大小不一样。 接下来我们来看看联合体

    double a;                 // 8       [0,7]
    int b;                    // 4       [8,9,10,11]
    char c;                   // 1       [12]
    short d;                  // 2       13, [14,15]
    int e;                    // 4       [16,17,18,19]
    struct LGStruct1 str;     // 24      20,21,22,23,[24,47]
}struct3;

a,b,c,d,e 的计算相比大家都会算了,str结构体大小为24,根据公式3中结构体套结构体,必须是其内部最⼤成员的整数倍,str中最大的是8,整数倍就是24开始。最后struct3的大小是48.

image.png

联合体

联合体又名共用体是把不同类型的数据组合成一个整体,其元素是互斥的,所有元素共占一段内存,只能又一个元素有值;如果对新元素赋值,则会将原来的元素值覆盖掉。
优点 : 所有元素共占同一片内存,所以节约内存,存储效率高,灵活.
缺点 : 所有元素都是互斥的,包容性差

创建一个联合体

union HHDemo {
    int a;
    double b;
    char c;
}demo;

联合体赋值

NSLog(@"大小 -- %lu",sizeof(demo));
demo.a = 10;
NSLog(@"a = %d - %f - %c",demo.a,demo.b,demo.c);
demo.b = 20.0;
NSLog(@"b = %d - %f - %c",demo.a,demo.b,demo.c);
demo.c = 'A';
NSLog(@"c = %d - %f - %c",demo.a,demo.b,demo.c);

打印结果

2021-10-28 23:23:42.578151+0800 003-联合体位域[22215:413826] 大小 -- 8

2021-10-28 23:23:42.578898+0800 003-联合体位域[22215:413826] a = 10 - 0.000000 -   - 0.000000

2021-10-28 23:23:42.578986+0800 003-联合体位域[22215:413826] b = 0 - 30.000000 -

2021-10-28 23:23:42.579041+0800 003-联合体位域[22215:413826] c = 65 - 30.000000 - A - 0.000000

2021-10-28 23:23:42.579088+0800 003-联合体位域[22215:413826] d = 1112014848 - 30.000004 -  - 50.000000

通过打印的结果好像元素之间并不是互斥的,给d赋值后,a,b 也有值,但是是错误的值,这是因为系统给的脏数据;