C语言中Union的用法
2016-04-02 12:01
169 查看
在C/C++程序的编写中,当多个基本数据类型或复合数据结构要占用同一片内存时,我们要使用联合体;当多种类型,多个对象,多个事物只取其一时(我们姑且通俗地称其为“n 选1”),我们也可以使用联合体来发挥其长处。
先看一段代码:
值代替了,就变为0了,这个时候要进行打印,就直接看内存里就行了,x的位置也就是k的位置是0,而y,z的位置的值没有改变,所以应该是0,5,6.
如果我们把上面的代码再稍微改一下:
我们看下内存模型
*------------------------------------------------------------------------------------------
* 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| 0 0 0 0 0 0 0 0
* x=4 |
y=5 |
z=6 执行完结构体的初始化内存中的值
*------------------------------------------------------------------------------------------
* x=0,i=0
| y=5 |
z=6 执行完i=0后内存中的值
*------------------------------------------------------------------------------------------
* x=1,i=1,j=1 | y=5
| z=6
执行完j=1后内存中的值
*------------------------------------------------------------------------------------------
*/
使用Union时几点值得注意的地方
1、联合里面那些东西不能存放?
我们知道,联合里面的东西共享内存,所以静态、引用都不能用,因为他们不可能共享内存。
2、类可以放入联合吗?
我们先看一个例子:
因为联合里不允许存放带有构造函数、析够函数、复制拷贝操作符等的类,因为他们共享内存,编译器无法保证这些对象不被破坏,也无法保证离开时调用析够函数。
3、又是匿名惹的祸??
我们先看下一段代码:
哈哈,问题在哪呢?让我们来看看构造test对象时发生了什么,当创建test对象时,自然要调用其相应的构造函数,在构造函数中当然要调用其成员的构造函数,所以其要去调用datatype成员的构造函数,但是他没有构造函数可调用,所以出错。
注意了,这里可并不是匿名联合!因为它后面紧跟了个data!
4、如何有效的防止访问出错?
使用联合可以节省内存空间,但是也有一定的风险:通过一个不适当的数据成员获取当前对象的值!例如上面的ch、i交错访问。
为了防止这样的错误,我们必须定义一个额外的对象,来跟踪当前被存储在联合中的值得类型,我们称这个额外的对象为:union的判别式。
一个比较好的经验是,在处理作为类成员的union对象时,为所有union数据类型提供一组访问函数。
先看一段代码:
union myun { struct { int x; int y; int z; }u; int k; }a; int main() { a.u.x =4; a.u.y =5; a.u.z =6; a.k = 0; printf("%d %d %d\n",a.u.x,a.u.y,a.u.z); return 0; }union类型是共享内存的,以size最大的结构作为自己的大小,这样的话,myun这个结构就包含u这个结构体,而大小也等于u这个结构体 的大小,在内存中的排列为声明的顺序x,y,z从低到高,然后赋值的时候,在内存中,就是x的位置放置4,y的位置放置5,z的位置放置6,现在对k赋 值,对k的赋值因为是union,要共享内存,所以从union的首地址开始放置,首地址开始的位置其实是x的位置,这样原来内存中x的位置就被k所赋的
值代替了,就变为0了,这个时候要进行打印,就直接看内存里就行了,x的位置也就是k的位置是0,而y,z的位置的值没有改变,所以应该是0,5,6.
如果我们把上面的代码再稍微改一下:
#include <stdio.h> typedef union test { struct { int x; int y; int z; }num; int i; int j; }test1; int main(int argc, char *argv[]) { test1 temp; temp.num.x = 4; temp.num.y = 5; temp.num.z = 6; temp.i = 0; temp.j = 1; printf("x=%d,y=%d,z=%d,i=%d,j=%d\n",temp.num.x,temp.num.y,temp.num.z,temp.i,temp.j); }这个时候输出的是什么呢?其实结果是x=1,y=5,z=6,i=1,j=1。
我们看下内存模型
*------------------------------------------------------------------------------------------
* 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| 0 0 0 0 0 0 0 0
* x=4 |
y=5 |
z=6 执行完结构体的初始化内存中的值
*------------------------------------------------------------------------------------------
* x=0,i=0
| y=5 |
z=6 执行完i=0后内存中的值
*------------------------------------------------------------------------------------------
* x=1,i=1,j=1 | y=5
| z=6
执行完j=1后内存中的值
*------------------------------------------------------------------------------------------
*/
使用Union时几点值得注意的地方
1、联合里面那些东西不能存放?
我们知道,联合里面的东西共享内存,所以静态、引用都不能用,因为他们不可能共享内存。
2、类可以放入联合吗?
我们先看一个例子:
class Test { public: Test():data(0) { } private: int data; }; typedef union _test { Test test; }UI;编译通不过,为什么呢?
因为联合里不允许存放带有构造函数、析够函数、复制拷贝操作符等的类,因为他们共享内存,编译器无法保证这些对象不被破坏,也无法保证离开时调用析够函数。
3、又是匿名惹的祸??
我们先看下一段代码:
class test { public: test(const char* p); test(int in); const operator char*() const { return data.ch; } operator long() const { return data.l; } private: enum type { Int, String }; union { const char* ch; int i; }datatype; type stype; test(test&); test& operator=(const test&); }; test::test(const char *p):stype(String),datatype.ch(p) { } test::test(int in):stype(Int),datatype.l(i) { }看出什么问题了吗?呵呵,编译通不过。为什么呢?难道datatype.ch(p)和datatype.l(i)有问题吗?
哈哈,问题在哪呢?让我们来看看构造test对象时发生了什么,当创建test对象时,自然要调用其相应的构造函数,在构造函数中当然要调用其成员的构造函数,所以其要去调用datatype成员的构造函数,但是他没有构造函数可调用,所以出错。
注意了,这里可并不是匿名联合!因为它后面紧跟了个data!
4、如何有效的防止访问出错?
使用联合可以节省内存空间,但是也有一定的风险:通过一个不适当的数据成员获取当前对象的值!例如上面的ch、i交错访问。
为了防止这样的错误,我们必须定义一个额外的对象,来跟踪当前被存储在联合中的值得类型,我们称这个额外的对象为:union的判别式。
一个比较好的经验是,在处理作为类成员的union对象时,为所有union数据类型提供一组访问函数。
相关文章推荐
- c++学习(2.2)变量
- C语言函数和汇编函数相互调用
- 几个有关iOS的几个常见问题-----为什么选择OC语言
- 设计类CDate以满足:输出年月日日期格式;输入的日期加1;设置日期(参考清华版李春葆C++书籍)
- C++中的输出格式 八进制 十进制 十六进制
- c++断言设置
- C++中构造函数或析构函数定义为private
- 第1周 C语言及程序设计初步 例程-7 问题求解方法——迭代
- C语言18个经典问题答录
- C++ 判断double变量是否为0
- [leetcode]326. Power of Three(c语言)
- 测试某一段程序运行时间的方法
- C++统计一个文件中每个数字字符(0~9)出现的次数
- C语言中的强符号和弱符号(变量篇)
- 第1周 C语言及程序设计初步 例程-6 用循环累加
- 一起talk C栗子吧(第一百三十五回:C语言实例--exec系列函数一)
- c++ 复数类
- 【笔试/面试】—— 奇葩 C/C++ 语法题
- C++类静态成员的使用
- C++开源库