20160403_联合体的本质和使用 & 与struct的不同 & 大端存储和小端存储
2016-04-03 14:36
288 查看
/************* 联合体的本质和使用 及 与struct的不同 及 大端存储和小端存储 ************
“联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。
【相似】
union,中文名“联合体、共用体”,在某种程度上类似结构体struct的一种数据结构,共用体(union)和结构体(struct)同样可以包含很多种数据类型和变量。
【不同】
在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
【初始化】
联合变量可以被初始化,但这个初始值必须是联合体第一个成员的类型,而且他必须位于一对花括号里面。
例如:
union {
int a;
float b;
char c[4];
}x = { 5 };
把x.a初始化为5。
我们不能把这个类量初始化为一个浮点值或字符值。如果给出的初始值是任何其他类型,他就会转换(如果可能的话)为一个整数并赋值给x.a。
【大端存储和小端存储】
Big-Endian和Little-Endian的定义如下:
1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
关于数的低位和高位:
例如:数0x1234,0x12是高位,0x34是低位
一个例子:
数:16bit宽的数0x1234
> 在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址
0x4000
0x4001
存放内容
0x34
0x12
> 而在Big-endian模式CPU内存中的存放方式则为:
内存地址
0x4000
0x4001
存放内容
0x12
0x34
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为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处理器还可以由硬件来选择是大端模式还是小端模式。
具体的存储模式依赖于具体的处理器。
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
short int x; // short int占用两个字节,系统会使用2个存储单元进行存储
char x0,x1; // 用来保存x的低地址
x=0x1122; // 用来保存x的高地址
x0=((char*)&x)[0]; // 低地址单元的存放内容
x1=((char*)&x)[1]; // 高地址单元的存放内容
******************************************************/
“联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。
【相似】
union,中文名“联合体、共用体”,在某种程度上类似结构体struct的一种数据结构,共用体(union)和结构体(struct)同样可以包含很多种数据类型和变量。
【不同】
在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
【初始化】
联合变量可以被初始化,但这个初始值必须是联合体第一个成员的类型,而且他必须位于一对花括号里面。
例如:
union {
int a;
float b;
char c[4];
}x = { 5 };
把x.a初始化为5。
我们不能把这个类量初始化为一个浮点值或字符值。如果给出的初始值是任何其他类型,他就会转换(如果可能的话)为一个整数并赋值给x.a。
【大端存储和小端存储】
Big-Endian和Little-Endian的定义如下:
1) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
2) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
关于数的低位和高位:
例如:数0x1234,0x12是高位,0x34是低位
一个例子:
数:16bit宽的数0x1234
> 在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址
0x4000
0x4001
存放内容
0x34
0x12
> 而在Big-endian模式CPU内存中的存放方式则为:
内存地址
0x4000
0x4001
存放内容
0x12
0x34
为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为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处理器还可以由硬件来选择是大端模式还是小端模式。
具体的存储模式依赖于具体的处理器。
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
short int x; // short int占用两个字节,系统会使用2个存储单元进行存储
char x0,x1; // 用来保存x的低地址
x=0x1122; // 用来保存x的高地址
x0=((char*)&x)[0]; // 低地址单元的存放内容
x1=((char*)&x)[1]; // 高地址单元的存放内容
******************************************************/
#include<stdio.h> union _x { int a; double b; }; struct _y { int a; double b; }; union _z { int i; char chs[4]; }; int main() { union _x xx; // union的size是其中最大成员的size printf("before size = %d\n",sizeof(xx)); // 共享内存:union中的变量同时共用同一段内存区,每次给某个成员赋值,该成员就占用该段内存区,该变量赋入新值则冲去其他变量的旧值 xx.a = 1; printf("xx.a = %d\n",xx.a); xx.b = 2; printf("xx.a = %d\n",xx.a); // union 的所有变量共用同一个首地址 printf("adress of a = %p\n",&xx.a); printf("adress of b = %p\n",&xx.b); printf("after size = %d\n",sizeof(xx)); // union 的大端存储和小端存储 union _z zz; zz.chs[0] = 0x00; zz.chs[1] = 0x01; zz.chs[2] = 0x02; zz.chs[3] = 0x03; // 数组中下标低的,地址也低,按地址从低到高,内存内容依次为:00,01,02,03,总共四字节 // 把四个字节作为一个整体(不分类型,直接打印十六进制),从内存高地址到低地址看,应为:0x03020100,低位00放在低地址上。 // 如果是小端存储,将打印出0x03020100;如果是大端存储,将打印出0x00010203 printf("%p \n",zz.i); printf("\n\n"); struct _y yy; // struct的size是其所有成员的size之和,也就是struct将为每一个成员分配存储空间而不论是否使用 printf("before size = %d\n",sizeof(yy)); return 1; }
相关文章推荐
- ACM-水题 吃糖果
- mesos 集群安装部署zookeeper(2)
- Tsinsen A1105 挖地雷
- java编程小记
- java编程小记
- JAVA Exception Handing
- 安卓登录页面的布局
- 我们就这样匆匆忙忙的赚了几亿美金
- ACM-水题 Higher Math
- hdoj 2028 Lowest Common Multiple Plus (最小公倍数,最大公约数)
- CDN缓存策略FAQ及更新频率
- 增加多层标签数量
- Cocos2d-x 3.9教程:5. Cocos2d-X中事件添加回调的方法
- 如何做好全屏化的交互体验(解决EditText导致的界面上移、挡住等问题)
- Notepad++简单配置c#开发
- SQL SERVER 2008 R2数据库出现“远程过程调用失败”(0x800706be)错误,怎么办!!
- 广播接收者Broadcast Receiver
- 207. Course Schedule 图的dfs算法
- mesos 集群安装部署规划、准备(1)
- Morris Traversal方法遍历