2024年最新联合体(union)的使用方法及其本质(1),从外包月薪5K到阿里月薪15K

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

int main(){
union var v;
v.l = 5;
printf(“%ld\n”,v.l);
v.i = 6;
}



**3.联合体union和大小端(big-endian、little-endian):**  
 下边示范了一种用途,代表四个含义的四个变量,但是可以用一个int来操作,直接int赋值,无论内存访问(指针大小的整数倍,访问才有效率),还是时间复杂度(一次和四次的区别,而且这四次有三次都是不整齐的地址),都会低一些。




#include<stdio.h>
union var{
char c[4];
int i;
};

int main(){
union var data;
data.c[0] = 0x04;//因为是char类型,数字不要太大,算算ascii的范围~
data.c[1] = 0x03;//写成16进制为了方便直接打印内存中的值对比
data.c[2] = 0x02;
data.c[3] = 0x11;
//数组中下标低的,地址也低,按地址从低到高,内存内容依次为:04,03,02,11。总共四字节!
//而把四个字节作为一个整体(不分类型,直接打印十六进制),应该从内存高地址到低地址看,0x11020304,低位04放在低地址上。
printf(“%x\n”,data.i);
}


  
 结果:  
 11020304  
 证明我的32位linux是小端(little-endian)






  
**4.联合体union所占内存空间大小:**  
  
 前边说了,首先,union的首地址是固定的,那么,union到底总共有多大?根据一些小常识,做个不严谨不高深的基础版验证吧。  
  
 根据:分配栈空间的时候内存地址基本上是连续的,至少同类型能保证在一起,连续就说明,我如果弄三个结构体出来,他们三个地址应该连着,看一下三个地址的间隔就知道了。



#include<stdio.h>
union sizeTest{
int a;
double b;
};
main(){
union sizeTest unionA;
union sizeTest unionB;
union sizeTest unionC;

    printf("the initial address of unionA is %p\n",&unionA);
    printf("the initial address of unionB is %p\n",&unionB);
    printf("the initial address of unionC is %p\n",&unionC);

}



  
 打印,可以看到结果:  
  
 the initial address of unionA is 0xbf9b8df8  
 the initial address of unionB is 0xbf9b8e00  
 the initial address of unionC is 0xbf9b8e08  
  
 很容易看出,8,0,8,这间隔是8字节,按double走的。  
  
 怕不保险,再改一下,把int改成数组,其他不变:







union sizeTest{
int a[10];
double b;
};



  
  
  
 打印  
  
 the initial address of unionA is 0xbfbb7738  
 the initial address of unionB is 0xbfbb7760  
 the initial address of unionC is 0xbfbb7788  
  
 88-60=28  
 60-38=28  
 算错了?我说的可是16进制0x。那么0x28就是40个字节,正好是数组a的大小。




忘了提一个功能——**sizeof()**


用sizeof直接看,就知道union的大小了




printf(“the sizeof   of unionA is %d\n”,sizeof(unionA));
        printf(“the sizeof   of unionB is %d\n”,sizeof(unionB));
        printf(“the sizeof   of unionC is %d\n”,sizeof(unionC));
printf(“the sizeof of union is %d\n”,sizeof(union sizeTest));



**上边说的地址规律,没有特定规则,也可能和你的编译器有关。另外,那只是栈空间,还可以主动申请堆空间,当然,堆空间就没有连续不连续一说了。**



  
**5.联合体union适用场合:**  
  
 有了前边那个验证,基本可以确认,union的内存是照着里边占地儿最大的那个变量分的。  
  
 也就可以大胆的推测一下,这种union的使用场合,是各数据类型各变量占用空间差不多并且对各变量同时使用要求不高的场合(单从内存使用上,我觉得没错)。  
  
 像上边做的第二个测试,一个数组(或者更大的数组int a[100]),和一个或者几个小变量写在一个union里,实在没什么必要,节省的空间太有限了,还增加了一些风险(最少有前边提到的逻辑上的风险)。所以,从内存占用分析,这种情况不如直接struct。



不过话说回来,某些情况下虽然不是很节约内存空间,但是union的复用性优势依然存在啊,比如方便多命名,这种“二义性”,从某些方面也可能是优势。这种方法还有个好处,就是某些寄存器或通道大小有限制的情况下,可以分多次搬运。




**6.本质&进阶:**



根据**union固定首地址**和**union按最大需求开辟一段内存空间**两个特征,可以发现,所有表面的定义都是虚的,所谓联合体union,就是在内存给你划了一个足够用的空间,至于你怎么玩~它不管~!(何止是union和struct,C不就是玩地址么,所以使用C灵活,也容易犯错)



没错,union的成员变量是相当于开辟了几个访问途径(即union包含的变量)!但是,没开辟的访问方式就不能用了?当然也能用!


写个小测试:



#include<stdio.h>
union u{
int i;
double d;//这个union有8字节大小
};
main(){
union u uu;
uu.i = 10;
printf(“%d\n”,uu.i);

    char * c;
    c = (char *)&uu;//把union的首地址赋值、强转成char类型
    c[0] = 'a';
    c[1] = 'b';
    c[2] = 'c';
    c[3] = '\0';
    c[4] = 'd';
    c[5] = 'e';

//最多能到c[7]
 printf(“%s\n”,c);//利用结束符’\0’打印字符串"abc"
printf(“%c %c %c %c %c %c\n”,c[0],c[1],c[2],c[3],c[4],c[5]);
}


一个例子了然,我的结构体只定义了int和double“接口”,只要我获得地址,往里边扔什么数据谁管得到?这就是C语言(不止union)的本质——只管开辟一段空间。



**但是你获取地址并访问和存取的数据,最好确定是合法(语法)合理(用途符合)的地址,不然虽然能操作,后患无穷,C的头疼之处,可能出了问题你都找不到。**




最近发现博客盗版严重(尤其是[C结构体](https://bbs.csdn.net/topics/618668825)这篇),允许正规转载,欢迎举报盗版,感谢。[博客](https://bbs.csdn.net/topics/618668825)<https://blog.csdn.net/huqinweI987/article/details/23597091>。


   
  


====================================================================================================================================



## 补充:




### 补充1:


解决一下捧场网友的困惑。


关于“有名”与“无名”联合体在结构体内所占空间的问题,其实这和是不是结构体无关,只和“有名”、“无名”有关,而且有名无名也是表象,其实是声明类型与定义变量的区别,看例子,直接打印,






#include <stdio.h>
struct s1{
union u{
int i;
};
struct ss1{
int i;
};
};

struct s2{
union{
int i;
};
struct{
int i2;
};
};

struct s3{//the same to s2
union su3{
int i;
}su33;
struct ss3{
int i;
}ss33;
};

union su4{
int i;
};
struct ss4{
int i;
};
struct s4{//the same to s3
union su4 su44;
struct ss4 ss44;

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

.(img-ZjLniJiJ-1715673647297)]
[外链图片转存中…(img-ccBM2jc7-1715673647297)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值