C语言union关键字,union和struct区别
- union 关键字的用法与struct 的用法非常类似。
- union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。例子如下:
- union StateMachine
- {
- char character;
- int number;
- char *str;
- double exp;
- };
- 一个union 只配置一个足够大的空间以来容纳最大长度的数据成员,以上例而言,最大长度是double 型态,所以StateMachine 的空间大小就是double 数据类型的大小。
- 在C++里,union 的成员默认属性页为public。union 主要用来压缩空间。如果一些数据不可能在同一时间同时被用到,则可以使用union。
- 一、大小端模式对union 类型数据的影响
- 下面再看一个例子:
- union
- {
- int i;
- ];
- }*p, u;
- p =&u;
- p->a[] = 0x39;
- p->a[] = 0x38;
- p.i 的值应该为多少呢?
- 这里需要考虑存储模式:大端模式和小端模式。
- 大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
- 小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。
- union 型数据所占的空间等于其最大的成员所占的空间。对union 型的成员的存取都是相对于该联合体基地址的偏移量为0 处开始,也就是联合体的访问不论对哪个变量的存取都是从union 的首地址位置开始。如此一解释,上面的问题是否已经有了答案呢?
- 二、如何用程序确认当前系统的存储模式?
- 上述问题似乎还比较简单,那来个有技术含量的:请写一个C 函数,若处理器是Big_endian 的,则返回0;若是Little_endian 的,则返回1。
- 先分析一下,按照上面关于大小端模式的定义,假设int 类型变量i 被初始化为1。
- 以大端模式存储,其内存布局如下图:
- 以小端模式存储,其内存布局如下图:
- 变量i 占4 个字节,但只有一个字节的值为1,另外三个字节的值都为0。如果取出低地址上的值为0,毫无疑问,这是大端模式;如果取出低地址上的值为1,毫无疑问,这是小端模式。既然如此,我们完全可以利用union 类型数据的特点:所有成员的起始地址一致。
- 到现在,应该知道怎么写了吧?参考答案如下:
- int checkSystem( )
- {
- union check
- {
- int i;
- char ch;
- } c;
- c.i = ;
- );
- }
- 现在你可以用这个函数来测试你当前系统的存储模式了。当然你也可以不用函数而直接去查看内存来确定当前系统的存储模式。如下图:
- 图中0x01 的值存在低地址上,说明当前系统为小端模式。
- 不过要说明的一点是,某些系统可能同时支持这两种存储模式,你可以用硬件跳线或在编译器的选项中设置其存储模式。
- 留个问题:在x86 系统下,输出的值为多少?
- #include <stdio.h>
- intmain()
- {
- ]={,,,,};
- );
- );
- printf(],*ptr2);
- ;
- }
- 以前在学校学习C语言的时候一直搞不懂那个共用体union有什么用的。工作之后才发现它的一些妙用,现举例如下:
- . 为了方便看懂代码。
- 比如说想写一个3 * 3的矩阵,可以这样写:
- [ 注:下面用红色部分标记的地方是后来添加上去的,谢谢yrqing718的提醒!]
- struct Matrix
- {
- union
- {
- struct
- {
- float _f11, _f12, _f13, _f21, _f22, _f23, _f31, _f32, _f33;
- };
- ][];
- }_matrix;
- };
- struct Matrix m;
- 这两个东西共同使用相同的空间,所以没有空间浪费,在需要整体用矩阵的时候可以用
- m._matrix.f (比如说传参,或者是整体赋值等);需要用其中的几个元素的时候可以用m._matrix._f11那样可以避免用m.f[][](这样不大直观,而且容易出错)。
- . 用在强制类型转换上(比强制类型转换更加容易看懂)
- 下面举几个例子:
- (). 判断系统用的是big endian 还是 little endian(其定义大家可以到网上查相关资料,此略)
- #define TRUE 1
- #define FALSE 0
- #define BOOL int
- BOOL isBigEndian()
- {
- ; /* i = 0x00000001*/
- char c = *(char *)&i; /* 注意不能写成 char c = (char)i; */
- return (int )c != i;
- }
- 如果是little endian字节序的话,那个i = ;的内存从小到大依次放的是:0x01 0x00 0x00 0x00,如是,按照i的起始地址变成按照char *方式(1字节)存取,即得c = 0x01;
- 反之亦然
- 也许看起来不是很清晰,下面来看一下这个:
- BOOL isBigEndian()
- {
- union
- {
- int i;
- char c;
- }test;
- test.c = ;
- ;
- }
- 这里用的是union来控制这个共享布局,有个知识点就是union里面的成员c和i都是从低地址开始对齐的。同样可以得到如此结果,而且不用转换,清晰一些。
- 什么,不觉得清晰??那再看下面的例子:
- (). 将little endian下的long long类型的值换成 big endian类型的值。已经知道系统提供了下面的api:long htonl(long lg);作用是把所有的字节序换成大端字节序。因此得出下面做法:
- long long htonLL(long long lg)
- {
- union
- {
- struct
- {
- long low;
- long high;
- }val_1;
- long long val_2;
- }val_arg, val_ret;
- if ( isBigEndian() )
- return lg;
- val_arg.val_2 = lg;
- val_ret.val_1.low = htonl( val_arg.val_1.high );
- val_ret.val_1.high = htonl( val_arg.val_1.low );
- return val_ret.val_2;
- }
- 只要把内存结构的草图画出来就比较容易明白了。
- ().为了理解c++类的布局,再看下面一个例子。有如下类:
- class Test
- {
- public :
- float getFVal(){ return f;}
- private :
- int i;
- char c;
- float f;
- };
- Test t;
- 不能在类Test中增加代码,给对象中的f赋值7.0f.
- class Test_Cpy
- {
- public :
- float getVal(){ return f;}
- float setVal(float f){ this ->f = f;}
- private :
- int i;
- char c;
- float f;
- };
- ....
- int main()
- {
- Test t;
- union
- {
- Test t1,
- Test_Cpy t2;
- }test;
- test.t2.setVal(7.0f);
- t = test.t1;
- assert( t.getVal() == 7.0f );
- ;
- }
- 说明:因为在增加类的成员函数时候,那个类的对象的布局基本不变。因此可以写一个与Test类一样结构的类Test_Cpy,而多了一个成员函数setVal,再用uinon结构对齐,就可以给私有变量赋值了。(这种方法在有虚机类和虚函数机制时可能失灵,故不可移植)至于详细的讨论,网上有,这个例子在实际中没有用途,只是用来考察这个内存布局的使用而已.
- union在操作系统底层的代码中用的比较多,因为它在内存共赏布局上方便且直观。所以网络编程,协议分析,内核代码上有一些用到union都比较好懂,简化了设计。
- 联合体与结构体是很容易混淆的概念。粗略一看,两者无论声明、定义还是定义对象的方式都很相似。然而这两个东西的概念和作用实际千差万别。
- 首先,联合体的各个成员共用内存,并应该同时只能有一个成员得到这块内存的使用权(即对内存的读写),而结构体各个成员各自拥有内存,各自使用互不干涉。所以,某种意义上来说,联合体比结构体节约内存。
- 举个例子:
- typedef struct
- {
- int i;
- int j;
- }A;
- typedef union
- {
- int i;
- double j;
- }U;
- sizeof(A)的值是8,sizeof(U)的值也是8(不是12)。
- 为什么sizeof(U)不是12呢?因为union中各成员共用内存,i和j的内存是同一块。而且整体内存大小以最大内存的成员的划分。即U的内存大小是double的大小,为8了。sizeof(A)大小为8,因为struct中i和j各自得到了一块内存,每人4个字节,加起来就是8了。
- 了解了联合体共用内存的概念,也就是明白了为何每次只能对其一个成员赋值了,因为如果对另一个赋值,会覆盖了上一个成员的值。
- 例如:书包;可以放置书本、笔盒、记事本等物。
- 联合体,仅能放入一样东西的包(限制),其尺寸,是可放物品中,最大一件的体积。
- 结构体,是能放入所有物品的包,所以其尺寸,可同时容纳多样物品。
- 联合体,同时间只能有一个成员在内。或是说,可以用不同型态,去看同一组数据。
- 结构体,可以包含多个成员在一起,成员都能个别操作。
- struct和union结构体和联合体的区别(转)
- 共用体
- 构造数据类型,也叫联合体
- 用途:使几个不同类型的变量共占一段内存(相互覆盖)
- 结构体是一种构造数据类型
- 用途:把不同类型的数据组合成一个整体-------自定义数据类型
- ---------------------------------------------------------------
- 结构体变量所占内存长度是各成员占的内存长度的总和。
- 共同体变量所占内存长度是各最长的成员占的内存长度。
- 共同体每次只能存放哪个的一种!!
- 共同体变量中起作用的成员是尊后一次存放的成员,
- 在存入新的成员后原有的成员失去了作用!
- ---------------------------------------------------------------
- Structure 与 Union主要有以下区别:
- . struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个被选中的成员, 而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之 和。在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。Union变量的长度等于最长的成员的长度。
- . 对于union的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于struct的不同成员赋值是互不影响的。
- 举一个例子:
- 例:
- #include <stdio.h>
- void main()
- {
- union{ /*定义一个联合*/
- int i;
- struct{ /*在联合中定义一个结构*/
- char first;
- char second;
- }half;
- }number;
- number.i=0x4241; /*联合成员赋值*/
- printf("%c%c\n", number.half.first, number.half.second);
- number.half.first='a'; /*联合中结构成员赋值*/
- number.half.second='b';
- printf("%x\n", number.i);
- system("pause");
- }
- 输出结果为:
- AB
- 分析:
- union的成员是共用内存的
- union{
- int i;
- struct{
- char first;
- char second;
- }half;
- }number;
- number.i=0x4241;
- 在这里i 和 half结构是共用内存
- number.i=0x4241给i赋值后,内存中以二进制存储0100
- 按顺序对应到结构中
- halt.first= 转换成10进制就是66(字母A的asc码)
- halt.second= 转换成10进制是65 (字母B的asc码)
- 所以输出后就是 AB
- 下面同理了
- ==========================================================================
- 第一题:
- #include <stdio.h>
- union
- {
- int i;
- ];
- }a;
- void main()
- {
- a.x[] = ;
- a.x[] = ;
- printf("%d",a.i);
- }
- 答案:
- 第二题:
- main()
- {
- union{ /*定义一个联合*/
- int i;
- struct{ /*在联合中定义一个结构*/
- char first;
- char second;
- }half;
- }number;
- number.i=0x4241; /*联合成员赋值*/
- printf("%c%c\n", number.half.first, mumber.half.second);
- number.half.first='a'; /*联合中结构成员赋值*/
- number.half.second='b';
- printf("%x\n", number.i);
- getch();
- }
- 答案: AB
- C语言中的联合体(UNION)的概念是,联合体中的多种数据类型共享同一个内存空间。就拿你举的例子来说:
- union
- {
- int i;
- ];
- }a;
- 在联合体a中定义了两种数据类型,字符数组x以及整形变量i.其中整形变量是16位的,数组大小为2的字符数组为8X2=16位。如此一来,编译器便会为 联合体a在内存中开辟一个16位的空间,这个空间里存储联合体的数据,但是这个空间只有16位,它既是整形变量的数据,也是字符数组的数据。如果你的程序 从字符数组的角度解析这个空间,那么它就是两个字符,如果你的程序从整型的角度解析这个空间,那么它就是一个整数。
- 以你的程序为例子,现在已经开辟了一个16位的空间,然后我们假定现在空间还没有被赋值,为:
- 那么在运行完代码
- a.x[] = ;
- a.x[] = ;
- 之后,16位的空间变为:
- 然后程序运行
- printf("%d",a.i);
- 就是把联合体a当成一个整数来解析,而不是字符串数组。那么这样一来,程序就把这16位变成了一个完整的整数:
- ( )二进制 = ()十进制
- 注意,你可以看到程序在把16位弄成整数的时候把后面八位放在了前面,前面八位放在了后面。这个反序是计算机存储结构造成的,这个和联合体没有直接关系。如果感兴趣的话可以参考汇编语言。
- 就是这个道理。
- 第二个例子同样,
- union{ /*定义一个联合*/
- int i;
- struct{ /*在联合中定义一个结构*/
- char first;
- char second;
- }half;
- }number;
- 定义了联合体number,这个联合体有两种数据类型,整形i(16位),以及一个结构体(struct half)(2个char,16位)。所以编译器为这个联合体开辟一个16位的空间:
- 然后赋值:
- number.i=0x4241;
- 这个时候,联合体以整形的身份出现,16位的空间将被整体认为是一个整数赋值。
- 注意( )二进制。还记得刚才说的,计算机存储的时候是反着存的吗,先存低位,再存高位(参考汇编语言),因此16位地址被赋值位
- 然后
- printf("%c%c\n", number.half.first, mumber.half.second);
- 实际上是把16位空间以结构体half的角度解析,也就是两个char.
- 那么第一个:number.half.first = ()二进制 = ()十进制 = A(ASCII码)
- 同理number.half.second = B(ASCII码)
- 当然后头又给first和second赋值位"a"和"b",这样会把16位空间弄成是:
- 然后用
- printf("%x\n", number.i);
- 就是把16位看成整数,记住高地位反过来
- ( )二进制 = (0X6261)16进制
- 所以结果就是:0x6261.
- getch();
- 最后记得按任意键结束程序。
- 共用体
- 构造数据类型,也叫联合体
- 用途:使几个不同类型的变量共占一段内存(相互覆盖)
- 结构体是一种构造数据类型
- 用途:把不同类型的数据组合成一个整体-------自定义数据类型
- ---------------------------------------------------------------
- 结构体变量所占内存长度是各成员占的内存长度的总和。
- 共同体变量所占内存长度是各最长的成员占的内存长度。
- 共同体每次只能存放哪个的一种!!
- 共同体变量中起作用的成员是尊后一次存放的成员,
- 在存入新的成员后原有的成员失去了作用!
- ---------------------------------------------------------------
- Structure 与 Union主要有以下区别:
- . struct和union都是由多个不同的数据类型成员组成, 但在任何同一时刻, union中只存放了一个被选中的成员, 而struct的所有成员都存在。在struct中,各成员都占有自己的内存空间,它们是同时存在的。一个struct变量的总长度等于所有成员长度之和。在Union中,所有成员不能同时占用它的内存空间,它们不能同时存在。Union变量的长度等于最长的成员的长度。
- . 对于union的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于struct的不同成员赋值是互不影响的。
- 举一个例子:
- 例:
- #include <stdio.h>
- void main()
- {
- union{
- int i;
- struct{
- char first;
- char second;
- }half;
- }number;
- number.i=0x4241;
- printf("%c%cn", number.half.first, number.half.second);
- number.half.first='a';
- number.half.second='b';
- printf("%xn", number.i);
- }
- 输出结果为:
- AB
- 结构体由一个或者多个相同或者不同的类型的数据组成的一个数据结构,系统在分配空间是会为所有的数据分配空间,因此结构体占用的存储空间至少是他的所有数据的长度之和(由于数据对齐的问题,分配空间可能大于所有数据的长度和);联合体则是一种合并式的数据类型,它可以在不同的时刻存储联合体中定义的一个数据;他的存储空间是它的所有数据中最长的那个数据的长度;
- 比如:
- typedef struct {
- int a; //4个字节
- long b; //4个字节
- long long c; //8个字节
- char *d ; //4个字节
- char e; //4个字节,其中一个字节有效,其他为对齐需要
- }A;
- 这个结构体实际分配的空间是:24个字节;他的数据实例同时保存abcde五个数据
- typedef union{
- int a; //4个字节
- long b; //4个字节
- long long c; //8个字节
- char *d ; //4个字节
- char e; //4个字节,其中一个字节有效,其他为对齐需要
- }B;
- 这个联合体分配空间8个字节(c的长度),他的数据实例同时只能保存abcde中的一个
C语言union关键字,union和struct区别的更多相关文章
- union关键字及大小端模式
1. union 关键字 union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在 union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有 ...
- C语言学习笔记--struct 和 union关键字
1.struct关键字 C 语言中的 struct 可以看作变量的集合struct中的每个数据成员都有独立的存储空间. 结构体与柔性数组 (1)柔性数组即数组大小待定的数组 (2)C 语言中可以由结构 ...
- C和C++中结构体(struct)、联合体(union)、枚举(enum)的区别
C++对C语言的结构.联合.枚举 这3种数据类型进行了扩展. 1.C++定义的结构名.联合名.枚举名 都是 类型名,可以直接用于变量的声明或定义.即在C++中定义变量时不必在结构名.联合名.枚举名 前 ...
- C语言union关键字
union 关键字的用法与struct 的用法非常类似. union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间 ...
- Oracle之Union与Union all的区别
如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字.union(或称为联合)的作用是将多个结果合并在一起显示出来. union和unio ...
- union与union all 的区别
Union与Union All的区别 如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字.union(或称为联合)的作用是将多个结果合并 ...
- Union 与 Union all 区别
原创,请园长不要删 Sql查询统计时,很多时候用到了union 和 union all,union与union all的区别就是联合查询的时候union会去重,union all不会去重.本人用uni ...
- SQL Server函数---Union与Union All的区别
SQL Server函数---Union与Union All的区别 如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字.union(或称 ...
- Oracle中Union与Union All的区别(适用多个数据库)
Oracle中Union与Union All的区别(适用多个数据库) 如果我们需要将两个select语句的结果作为一个整体显示出来,我们就需要用到union或者union all关键字.union(或 ...
随机推荐
- MemSQL Start[c]UP 2.0 - Round 1 E - Three strings 广义后缀自动机
E - Three strings 将三个串加进去,看每个节点在三个串中分别出现了多少次. #include<bits/stdc++.h> #define LL long long #de ...
- 20172301 《Java软件结构与数据结构》实验一报告
20172301 <Java软件结构与数据结构>实验一报告 课程:<Java软件结构与数据结构> 班级: 1723 姓名: 郭恺 学号:20172301 实验教师:王志强老师 ...
- 历史文章分类汇总-Anaconda安装第三方包(whl文件)
本文主要是对公众号之前发布的文章进行分类整理,方面大家查阅,以后会不定期对文章汇总进行更新与发布. 一.推荐阅读: Anaconda安装第三方包(whl文件) 福布斯系列之数据分析思路篇 福布斯系 ...
- linux 设备文件和设备之间联系的建立
<设备驱动模型> 注:几乎所有的设备结构体都包含"strcut kobject kobj"和"srtuct list_head list"该结构体 ...
- HDU 5517 【二维树状数组///三维偏序问题】
题目链接:[http://acm.split.hdu.edu.cn/showproblem.php?pid=5517] 题意:定义multi_set A<a , d>,B<c , d ...
- 【Naive Splay Template】
写小作业的时候重新复习了一下splay 只支持插入,删除,查k大,查节点数.没有迭代器. T类型需要重载==和<,要调用拷贝构造函数. template<class T> class ...
- 【BZOJ】1864: [Zjoi2006]三色二叉树
1864: [Zjoi2006]三色二叉树 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 1295 Solved: 961[Submit][Status ...
- Windows下C语言调用dll动态链接库
dll是windows下的动态链接库文件,下面记录一下在windows下如何调用C语言开发的dll动态链接库. 1.dll动态链接库的源代码 hello_dll.c #include "st ...
- Python文件类型
Python的文件类型分为三种:源代码.字节代码.优化代码. 1. 源代码 Python源代码文件,即py脚本文件,由 python.exe 解释,可在控制台下运行.pyw脚本文件是图形用户接口 ...
- poj 1330 Nearest Common Ancestors 单次LCA/DFS
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 19919 Accept ...