结构体 联合体 位域

union 共用体/联合体

  1. 结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
  2. 结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

结构体字节对齐

其实字节对齐的细节和具体编译器实现相关,但一般而言,满足三个准则:

  1. 数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存储。 min(当前开始的位置m n)
  2. 结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.)
  3. 收尾⼯作:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤成员的整数倍.不⾜的要补⻬。
struct P1 {
    BOOL sex; // 2
    NSString * name1; // 8
    int age; // 4
};// 2 + (6 第二个成员8个字节,起始位置从8的整数倍开始开始 ) + 8 + 4 =  20  -> 8(最大成员的)的整数倍 24

struct P2{
    int age; // 4
    NSString * name1; // 8
    BOOL sex; // 2
};// 4 + (4 第二个成员8个字节,起始位置从8的整数倍开始开始 ) + 8 + 2 =  18  -> 8(最大成员的)的整数倍 24
struct P3{
    BOOL sex; // 2
    int age; // 4
    NSString * name1; // 8
};//  2 + (2) + 4 + 8 = 16  -> 16
struct P1 p1 ;
struct P2 p2 ;
struct P3 p3 ;
NSLog(@"%ld %ld  %ld", sizeof(p1), sizeof(p2), sizeof(p3));
// 输出  24  24 16

struct T1{
    int  a; // 8
    char b;
    struct P1 p;// 24 最大成员8
};// 4 + 2 + (2) + 24 = 32 -> 32

struct T2{
    char b;
    struct P1 p;// 24 最大成员8
};// 2 + (6 P1 的最大成员是8 起始从8的倍数开始) + 24 = 32 -> 32

struct T3{
    int  a; // 8
    char b;
    struct P4 p4; // 8 最大成员是4
};// 4 + 2 + (2) + 8 = 16 -> 16  最大成员是4 4的倍数

struct T4{
    char b;
    struct P4 p4; // 8 最大成员是4
};//  2 + (2) + 8 = 12 ->  最大成员是4,所以是4的倍数。12

结构体位域

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。比如一个Bool类型,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。

  • 位段成员必须声明为int、unsigned int或signed int类型(short char long)。
  • 位域可以无名,只用来填充不能访问
// 位域的格式
// 类型说明符 位域名:位域长度  
struct Person {
    int a1:2;
    int a2:5;
    int a3:7;
    int b1: 8;
    int b2:4;
    int c1:5;
    int c2: 6;
    int c3: 3;
    int c4: 2;
};

(lldb) p/t t
(Test) $0 = {
  p = (a1 = 0b01, a2 = 0b00001, a3 = 0b0000001, b1 = 0b00000001, b2 = 0b0001, c1 = 0b00001, c2 = 0b000001, c3 = 0b001, c4 = 0b01)
  b = 0b000000000000000000000010010 0000100000100010000000100000010000101
  //在int 类型的 4字节长度(定义的类型)是一个整体,如果存不下将会从下一个字节开始存。位的的长度不能超多 4 * 8 的长度
  
  struct P1 {
    char c1: 4;
    char c2: 5;
    char c3: 6;
    char c4: 7;
};
 (lldb) p/t t
p1 = (c1 = 0b0001, c2 = 0b00001, c3 = 0b000001, c4 = 0b0000001)
  b = 0b00000001000000010000000100000001
  // 此时char 1个字节是一个整体。
  
  struct P2 {
    char c1: 5;
    int c2: 6;
    char c3: 6;
    char c4: 7;
};
 (lldb) p/t t
 p2 = (c1 = 0b00001, c2 = 0b000001, c3 = 0b000001, c4 = 0b0000001)
  b = 0b0000000000000000000000000000000000000001000000010000000000100001
  // 如果类型是不同的,当前存储室,当前的类型是一个整体,是否可以存放在后续的位置之内,
  // 比如 c2 是4个字节。从c1到4个字节(32位)剩余的位能够存储,则在后续存储。
  // 对于c3 char是1个字节。从c3 到当前的剩余1个字节整体不能存下c3.所以向后移动存在下一个字节(8位)中

位域存储的大致规则

  1. 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
  2. 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
  3. 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
  4. 如果位域字段之间穿插着非位域字段,则不进行压缩;
  5. 整个结构体的总大小为最宽基本类型成员大小的整数倍。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352