C语言union关键字

union 关键字的用法与struct 的用法非常类似。

union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置空间,在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。例子如下:

  1. union StateMachine
  2. {
  3. char character;
  4. int number;
  5. char *str;
  6. double exp;
  7. };

一个union 只配置一个足够大的空间以来容纳最大长度的数据成员,以上例而言,最大长度是double 型态,所以StateMachine 的空间大小就是double 数据类型的大小。

在C++里,union 的成员默认属性页为public。union 主要用来压缩空间。如果一些数据不可能在同一时间同时被用到,则可以使用union。

一、大小端模式对union 类型数据的影响

下面再看一个例子:

  1. union
  2. {
  3. int i;
  4. char a[2];
  5. }*p, u;
  6. p =&u;
  7. p->a[0] = 0x39;
  8. p->a[1] = 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 类型数据的特点:所有成员的起始地址一致。

到现在,应该知道怎么写了吧?参考答案如下:

  1. int checkSystem( )
  2. {
  3. union check
  4. {
  5. int i;
  6. char ch;
  7. } c;
  8. c.i = 1;
  9. return (c.ch ==1);
  10. }

现在你可以用这个函数来测试你当前系统的存储模式了。当然你也可以不用函数而直接去查看内存来确定当前系统的存储模式。如下图:

图中0x01 的值存在低地址上,说明当前系统为小端模式。

不过要说明的一点是,某些系统可能同时支持这两种存储模式,你可以用硬件跳线或在编译器的选项中设置其存储模式。

留个问题:在x86 系统下,输出的值为多少?

  1. #include <stdio.h>
  2. intmain()
  3. {
  4. int a[5]={1,2,3,4,5};
  5. int *ptr1=(int *)(&a+1);
  6. int *ptr2=(int *)((int)a+1);
  7. printf("%x,%x",ptr1[-1],*ptr2);
  8. return 0;
  9. }

本文转自:http://c.biancheng.net/cpp/html/450.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏极客编程

Vuex 2 入门与提高

计数器应用的数据模型很简单:使用一个counter属性来表示计数器的 当前值就够了。

541
来自专栏扎心了老铁

python concurrent.futures

python因为其全局解释器锁GIL而无法通过线程实现真正的平行计算。这个论断我们不展开,但是有个概念我们要说明,IO密集型 vs. 计算密集型。 IO密集型:...

3597
来自专栏進无尽的文章

编码篇-iOS程序中的内存分配 栈区堆区全局区等相关知识

在计算机的系统中,运行的应用程序中的数据都是保存在内存中,不同类型的数据,保存的内存区域不同。内存区域大致可以分为:栈区、堆区、全局区(静态区)、文字常量区、程...

842
来自专栏博客园

浅谈Await

   我们都知道Await关键字是.Net FrameWork4.5引入的特性。await使得我们使用异步更加时特别便捷,并且还不会导致线程堵塞。我们在使用时也...

752
来自专栏个人分享

HotSpot 自动内存管理笔记与实战

1.对象的创建 虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、...

844
来自专栏Java技术栈

详解 Java 中的三种代理模式

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即...

621
来自专栏java一日一条

一个Java对象到底占用多大内存

大家可以用这个代码边看边验证,注意的是,运行这个程序需要通过javaagent注入Instrumentation,具体可以看原博客。我今天主要是总结下手动计算J...

371
来自专栏me的随笔

C#异步编程

上面这段代码中,Main方法中的代码是按照自上而下的顺序执行的。网络状况不佳时,Start()方法是比较耗时(注意,这里在Start方法中调用了异步方法GetS...

723
来自专栏微信公众号:Java团长

Java的三种代理模式

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即...

381
来自专栏木木玲

JVM中 对象的内存布局 以及 实例分析

1878

扫码关注云+社区