打印
[牛人杂谈]

共用体union详解

[复制链接]
楼主: yiyigirl2014
手机看帖
扫描二维码
随时随地手机跟帖
21
位段来自于结构体,位段的声明和结构体类似,但它的成员是一个多或多个位的字段。这些不同长度的字段实际上存储于一个或多个整型变量中。位段的声明必须是int、signed int或unsigned int,考虑到移植性,一般选择后两个。
一个位段声明的例子:
struct CHAR
{
unsigned ch:7;
signed font:6;
unsigned size:19;
//char *p;//若不是位段则可以定义为其他类型
};//位段长度与机器有关,x86系统为32位,x86_64为64位
struct CHAR ch;//定义一个位段,
如下为位段的存储结构
ch(7bit)
font(6bit)
size(19bit)
有些机器的存储结构
如下:
size(19bit)
font(6bit)
ch(7bit)
这也是使用位段在移植性方面需要考虑到的问题。
对位段的赋值需要注意的是位宽问题
例如:
ch.font=63;
printf(“%d”,ch.font);
输出结果:-1
这是因为63=(00000000 00000000 00000000 00111111)2,font变量仅有6位,所以赋值时会截取低位的6位,同时font高位为符号位,因此结果为-1。
注意:使用位段只是基于方便的目的。任何可以用位段实现的任务都可以使用移位和屏蔽来实现,同时使用位段还要考虑到移植性问题,因此在一个程序在是否使用位段需要进行权衡。

使用特权

评论回复
22
yiyigirl2014|  楼主 | 2016-4-28 10:30 | 只看该作者
在好多头文件上都是用共用体来定义位的操作和端口的操作的。可以按位段定义

使用特权

评论回复
23
heisexingqisi| | 2016-4-28 22:54 | 只看该作者
当需要把不同类型的变量存放到同一段内存单元或对同一段内存单元的数据按不同类型处理则需要使用共用体数据结构

使用特权

评论回复
24
zhuotuzi| | 2016-4-28 23:27 | 只看该作者
共用体各成员占相同的起始地址所占内存长度等于最长的成员所占内存
结构体各成员占不同的地址所占内存长度等于全部成员所占内存之和

使用特权

评论回复
25
gejigeji521| | 2016-4-29 21:33 | 只看该作者
在搞单片机时候,要试着通过结构体和联合体来传递参数,初始化变量,这样可以提高能力,而且写的代码质量高

使用特权

评论回复
26
huangcunxiake| | 2016-4-29 22:26 | 只看该作者
union 型数据所占的空间等于其最大的成员所占的空间。对union 型的成员的存取都是相对于该联合体基地址的偏移量为0 处开始,也就是联合体的访问不论对哪个变量的存取都是从union 的首地址位置开始。

使用特权

评论回复
27
天灵灵地灵灵| | 2016-4-30 12:48 | 只看该作者
共用体和结构体应该都是通过相同的方式访问成员的,比如用"."

使用特权

评论回复
28
yiyigirl2014|  楼主 | 2016-5-17 21:34 | 只看该作者
在做这个的时候,就要画出来,然后才好分配空间。

使用特权

评论回复
29
643757107| | 2016-5-18 10:52 | 只看该作者
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

使用特权

评论回复
30
643757107| | 2016-5-18 10:53 | 只看该作者
大小端模式
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。

图解
对于0x11223344 储存如下


使用特权

评论回复
31
643757107| | 2016-5-18 10:54 | 只看该作者
名字由来
乔纳森·斯威夫特的著名讽刺小说《格列夫游记》中,小人国内部分裂成Big-endian和Little-endian两派,区别在于一派要求从**蛋的大头把**蛋打破,另一派要求从**蛋的小头把**蛋打破。斯威夫特借以讽刺英国的政党之争,在计算机工业中指数据储存顺序的分歧。

编辑器模式
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
short int x;
char x0,x1;
x=0x1122;
x0=((char*)&x)[0]; //低地址单元
x1=((char*)&x)[1]; //高地址单元
若x0=0x11,则是大端; 若x0=0x22,则是小端......
上面的程序还可以看出,数据寻址时,用的是低位字节的地址。

简单大小端转换的宏
#definesw16(x)\
  ((short)(\
  (((short)(x)&(short)0x00ffU)<<8)|\
  (((short)(x)&(short)0xff00U)>>8)))


使用特权

评论回复
32
643757107| | 2016-5-18 10:55 | 只看该作者
static union { char c[4]; unsigned long l; } endian_test = { { 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
(如果ENDIANNESS=’l’表示系统为little endian,为’b’表示big endian )。

使用特权

评论回复
33
643757107| | 2016-5-18 10:55 | 只看该作者
本帖最后由 643757107 于 2016-5-18 10:58 编辑

在英特尔处理器,Windows10操作系统上,对话框显示的结果是99 FB E4 15,与直接求出来的16进制值15 E4 FB 99正好相反,所以是小端的。
[size=1em]
[size=1em][size=1em]include <iostream>

[size=1em]using namespace std;


[size=1em]typedef unsigned char byte;


[size=1em]// 转换char(视为整数类型)为16进制字符串

[size=1em]void ChtoHex(byte Val, char* dest)

[size=1em]{

[size=1em]    // 辗转相除法,倒序看得到结果


[size=1em]    byte tmp = Val % 16;

[size=1em]    if (tmp >= 0 && tmp <= 9)

[size=1em]    {

[size=1em]        dest[1] = '0' + tmp;

[size=1em]    }

[size=1em]    else if (tmp >= 10 && tmp <= 15)

[size=1em]    {

[size=1em]        dest[1] = 'A' + tmp - 10;

[size=1em]    }


[size=1em]    tmp = (Val/16) % 16;

[size=1em]    if (tmp >= 0 && tmp <= 9)

[size=1em]    {

[size=1em]        dest[0] = '0' + tmp;

[size=1em]    }

[size=1em]    else if (tmp >= 10 && tmp <= 15)

[size=1em]    {

[size=1em]        dest[0] = 'A' + tmp - 10;

[size=1em]    }


[size=1em]    // 设置'\0'

[size=1em]    dest[2] = '\0';

[size=1em]}


[size=1em]// 主函数

[size=1em]int main()

[size=1em]{

[size=1em]    int u = 367328153; // 原始数据,8位16进制为15 E4 FB 99

[size=1em]    byte a, b, c, d;   // u从低地址到高地址的四个字节

[size=1em]    // a~d对应的16进制字符串,预留3个字符

[size=1em]    char Sa[3], Sb[3], Sc[3], Sd[3];


[size=1em]    byte* k = (byte*)&u;

[size=1em]    a = k[0];

[size=1em]    b = k[1];

[size=1em]    c = k[2];

[size=1em]    d = k[3];


[size=1em]    // 转成16进制字符串

[size=1em]    ChtoHex(a, Sa);

[size=1em]    ChtoHex(b, Sb);

[size=1em]    ChtoHex(c, Sc);

[size=1em]    ChtoHex(d, Sd);


[size=1em]    cout << Sa << " " << Sb << " " << Sc << " " << Sd << endl;


[size=1em]    system("pause");

[size=1em]    return 0;

[size=1em]}




在英特尔处理器,Windows10操作系统上,控制台显示的结果是99 FB E4 15,与直接求出来的16进制值15 E4 FB 99正好相反,所以也证明是小端的。

使用特权

评论回复
34
643757107| | 2016-5-18 11:06 | 只看该作者
上面的配色是不是很好看,淡灰蓝色的字体,配上黑色背景,看起来不刺眼又很清晰赏心悦目。

使用特权

评论回复
35
yiyigirl2014|  楼主 | 2016-5-18 22:36 | 只看该作者
我换成Linux系统了,一样看着挺不错的,用Linux系统不卡。

使用特权

评论回复
36
捉虫天师| | 2016-7-30 16:38 | 只看该作者
不建议程序中出现使用这些, 搞不好移植性差了。

使用特权

评论回复
37
稳稳の幸福| | 2016-7-30 17:17 | 只看该作者
共用体各成员占相同的起始地址所占内存长度等于最长的成员所占内存

使用特权

评论回复
38
yiyigirl2014|  楼主 | 2016-7-30 17:44 | 只看该作者
在好多头文件上都是用共用体来定义位的操作和端口的操作的。可以按位段定义

使用特权

评论回复
39
mintspring| | 2016-7-30 20:11 | 只看该作者
使用覆盖技术,几个变量相互覆盖,从而使几个不同变量共占同一段内存的结构,成为共同体类型的结构。
共同体的定义类似结构体,不过共同体的所有成员都在同一段内存中存放,起始地址一样,并且同一时刻只能使用其中的一个成员变量。

使用特权

评论回复
40
zhuotuzi| | 2016-7-31 21:32 | 只看该作者
共用体常用来节省内存,特别是一些嵌入式编程,内存是非常宝贵的!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则