C语言编程中的联合体union入门学习教程_C 语言

联合体(union)在C语言中是一个特殊的数据类型,能够存储不同类型的数据在同一个内存位置。可以定义一个联合体使用许多成员,但只有一个部件可以包含在任何时候给定的值。联合体会提供使用相同的存储器位置供多用途的有效方式。

定义联合体
要定义联合体,必须使用union语句很相似于定义结构。联合体声明中定义了一个新的数据类型,程序不止一个成员。联合体声明的格式如下:

union [union tag]
{
  member definition;
  member definition;
  ...
  member definition;
} [one or more union variables];

union标签是可选的,每个成员的定义是一个正常的变量定义,如 int i; 和 float f; 或任何其他有效的变量的定义。在联合体定义的结尾,最后分号之前,可以指定一个或多个变量的联合,但它是可选的。这里定义一个名为数据联合类型有三个成员 i, f, 和 str:

union Data
{
  int i;
  float f;
  char str[20];
} data;

现在,数据类型的变量可以存储的整数,一个浮点数,或字符的字符串。这意味着一个单可变结构即相同的存储单元可用于存储多个类型的数据。可以使用任何内置或用户定义的数据类型根据需要在联合里面。

通过union所占用的内存将大到足以容纳联合体的最大成员。例如,在上面的例子中的数据类型将占用20个字节的存储空间,因为这是通过文字串所占用的最大空间。以下将显示由上述联合共占用内存大小的例子:

#include <stdio.h>
#include <string.h>

union Data
{
  int i;
  float f;
  char str[20];
};

int main( )
{
  union Data data;    

  printf( "Memory size occupied by data : %d
", sizeof(data));

  return 0;
}

让我们编译和运行上面的程序,这将产生以下结果:

Memory size occupied by data : 20

访问联合体成员
要访问联合体的任何成员,我们使用成员访问运算符(.)。成员访问运算符编码为联合体变量名和成员,访问时使用union关键字定义联合体类型的变量。以下为例子来解释联合体的用法:

#include <stdio.h>
#include <string.h>

union Data
{
  int i;
  float f;
  char str[20];
};

int main( )
{
  union Data data;    

  data.i = 10;
  data.f = 220.5;
  strcpy( data.str, "C Programming");

  printf( "data.i : %d
", data.i);
  printf( "data.f : %f
", data.f);
  printf( "data.str : %s
", data.str);

  return 0;
}

让我们编译和运行上面的程序,这将产生以下结果:

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

在这里,我们可以看到,联合体成员i 和f 值被损坏,因为分配给变量终值已占用的内存位置,如果str成员的值被很好的打印的原因。现在,让我们来再一次看看同样的例子,我们将使用一个变量在同一时间,它是联合体的主要目的:

#include <stdio.h>
#include <string.h>

union Data
{
  int i;
  float f;
  char str[20];
};

int main( )
{
  union Data data;    

  data.i = 10;
  printf( "data.i : %d
", data.i);

  data.f = 220.5;
  printf( "data.f : %f
", data.f);

  strcpy( data.str, "C Programming");
  printf( "data.str : %s
", data.str);

  return 0;
}

让我们编译和运行上面的程序,这将产生以下结果:

data.i : 10
data.f : 220.500000
data.str : C Programming

这里,所有的成员都得到打印得非常好,因为一个部件被一次使用。

应用场合
当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C Programming Language 一书中对于联合体是这么描述的:

     1)联合体是一个结构;

     2)它的所有成员相对于基地址的偏移量都为0;

     3)此结构空间要大到足够容纳最"宽"的成员;

     4)其对齐方式要适合其中所有的成员;

下面解释这四条描述:

     由于联合体中的所有成员是共享一段内存的,因此每个成员的存放首地址相对于于联合体变量的基地址的偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,因此该空间必须足够容纳这些成员中最宽的成员。对于这句“对齐方式要适合其中所有的成员”是指其必须符合所有成员的自身对齐方式。

下面举例说明:

如联合体

union U
{
  char s[9];
  int n;
  double d;
};

s占9字节,n占4字节,d占8字节,因此其至少需9字节的空间。然而其实际大小并不是9,用运算符sizeof测试其大小为16.这是因为这里存在字节对齐的问题,9既不能被4整除,也不能被8整除。因此补充字节到16,这样就符合所有成员的自身对齐了。从这里可以看出联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系,即其大小必须满足两个条件:1)大小足够容纳最宽的成员;2)大小能被其包含的所有基本数据类型的大小所整除。

测试程序:

/*测试联合体 2011.10.3*/

#include <iostream>
using namespace std;

union U1
{
  char s[9];
  int n;
  double d;
};

union U2
{
  char s[5];
  int n;
  double d;
};

int main(int argc, char *argv[])
{
  U1 u1;
  U2 u2;
  printf("%d\n",sizeof(u1));
  printf("%d\n",sizeof(u2));
  printf("0x%x\n",&u1);
  printf("0x%x\n",&u1.s);
  printf("0x%x\n",&u1.n);
  printf("0x%x\n",&u1.d);
  u1.n=1;
  printf("%d\n",u1.s[0]);
  printf("%lf\n",u1.d);
  unsigned char *p=(unsigned char *)&u1;
  printf("%d\n",*p);
  printf("%d\n",*(p+1));
  printf("%d\n",*(p+2));
  printf("%d\n",*(p+3));
  printf("%d\n",*(p+4));
  printf("%d\n",*(p+5));
  printf("%d\n",*(p+6));
  printf("%d\n",*(p+7));
  return 0;
}

输出结果为:

16
8
0x22ff60
0x22ff60
0x22ff60
0x22ff60
1
0.000000
1
0
0
0
48
204
64
0
请按任意键继续. . .

对于sizeof(u1)=16。因为u1中s占9字节,n占4字节,d占8字节,因此至少需要9字节。其包含的基本数据类型为char,int,double分别占1,4,8字节,为了使u1所占空间的大小能被1,4,8整除,则需填充字节以到16,因此sizeof(u1)=16.

对于sizeof(u2)=8。因为u2中s占5字节,n占4字节,d占8字节,因此至少需要8字节。其包含的基本数据类型为char,int,double分别占1,4,8字节,为了使u2所占空间的大小能被1,4,8整除,不需填充字节,因为8本身就能满足要求。因此sizeof(u2)=8。

从打印出的每个成员的基地址可以看出,联合体中每个成员的基地址都相同,等于联合体变量的首地址。

对u1.n=1,将u1的n赋值为1后,则该段内存的前4个字节存储的数据为00000001 00000000 00000000 00000000

因此取s[0]的数据表示取第一个单元的数据,其整型值为1,所以打印出的结果为1.

至于打印出的d为0.000000愿意如下。由于已知该段内存前4字节的单元存储的数据为00000001 00000000 00000000 00000000,从上面打印结果48,204,64,0可以知道后面4个字节单元中的数据为00110000 11001100 01000000 00000000,因此其表示的二进 制浮点数为

00000000 01000000 11001100 00110000 00000000 00000000 00000000 00000001

对于double型数据,第63位0为符号位,62-52 00000000100为阶码,0000 11001100 00110000 00000000 00000000 00000000 00000001为尾数,根据其值知道尾数值约为0,而阶码为4-1023=-1019,因此其表示的浮点数为1.0*2^(-1019)=0.00000000000......,因此输出结果为0.000000。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c语言
, 入门
, C语言入门
联合体
,以便于您获取更多的相关知识。

时间: 2024-09-28 11:25:04

C语言编程中的联合体union入门学习教程_C 语言的相关文章

C++编程中new运算符的使用学习教程_C 语言

new运算符用作从自由存储为 type-name 的对象或对象数组分配内存,并将已适当分类的非零指针返回到对象. [::] new [placement] new-type-name [new-initializer] [::] new [placement] ( type-name ) [new-initializer] 备注如果不成功,则 new 将返回零或引发异常:有关详细信息,请参阅 new 和 delete 运算符. 通过编写自定义异常处理例程并调用 _set_new_handler

C++编程中的数据类型和常量学习教程_C 语言

C++数据类型计算机处理的对象是数据,而数据是以某种特定的形式存在的(例如整数.浮点数.字符等形式).不同的数据之间往往还存在某些联系(例如由若干个整数组成一个整数数组).数据结构指的是数据的组织形式.例如,数组就是一种数据结构.不同的计算机语言所允许使用的数据结构是不同的.处理同一类问题,如果数据结构不同,算法也会不同.例如,对10个整数排序和对包含10个元素的整型数组排序的算法是不同的. C++的数据包括常量与变量,常量与变量都具有类型.由以上这些数据类型还可以构成更复杂的数据结构.例如利用

完全掌握C++编程中构造函数使用的超级学习教程_C 语言

构造函数是一种可初始化其类的实例的成员函数.构造函数具有与类相同的名称,没有返回值.构造函数可以具有任意数量的参数,类可以具有任意数量的重载构造函数.构造函数可以具有任何可访问性(公共.受保护或私有).如果未定义任何构造函数,则编译器会生成不采用任何参数的默认构造函数:可以通过将默认构造函数声明为已删除来重写此行为.构造函数顺序构造函数按此顺序执行工作: 按声明顺序调用基类和成员构造函数. 如果类派生自虚拟基类,则会将对象的虚拟基指针初始化. 如果类具有或继承了虚函数,则会将对象的虚函数指针初始

C语言中的结构体的入门学习教程_C 语言

C语言中数组允许定义类型的变量,可容纳相同类型的多个数据项,但结构体在C语言编程中,它允许定义不同种类的数据项可供其他用户定义的数据类型. 结构是用来代表一个记录,假设要跟踪图书馆的书籍.可能要跟踪有关每本书以下属性: Title - 标题 Author - 作者 Subject - 科目 Book ID - 编号 定义结构体定义一个结构体,必须使用结构体的struct语句.该struct语句定义了一个新的数据类型,程序不止一个成员.struct语句的格式是这样的: struct [struct

详解C语言编程中的函数指针以及函数回调_C 语言

函数指针: 就是存储函数地址的指针,就是指向函数的指针,就是指针存储的值是函数地址,我们可以通过指针可以调用函数. 我们先来定义一个简单的函数: //定义这样一个函数 void easyFunc() { printf("I'm a easy Function\n"); } //声明一个函数 void easyFunc(); //调用函数 easyFunc(); //定义这样一个函数 void easyFunc() { printf("I'm a easy Function\n

C语言中的函数指针基础学习教程_C 语言

顾名思义,函数指针就是函数的指针.它是一个指针,指向一个函数.看例子: A) char * (*fun1)(char * p1,char * p2); B) char * *fun2(char * p1,char * p2); C) char * fun3(char * p1,char * p2); 看看上面三个表达式分别是什么意思? C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型. B) 也很简单,与C)表达式相比,唯一不同的就是函数的

C语言中逻辑运算符与条件运算符的学习教程_C 语言

逻辑运算符 逻辑运算符,用于对包含关系运算符的表达式进行组合,形成新的表达式:结果也是只有真或假两种情况,结果值用 BOOL 类型变量存储. 运算符 解释 结合方式 () [] -> . 括号(函数等),数组,两种结构成员访问 由左向右 ! ~ ++ -- + -  * & (类型) sizeof 否定,按位否定,增量,减量,正负号, 间接,取地址,类型转换,求大小 由右向左 * / % 乘,除,取模 由左向右 + - 加,减 由左向右 << >> 左移,右移 由左向

讲解C语言编程中指针赋值的入门实例_C 语言

从const int i 说起 你知道我们声明一个变量时象这样int i :这个i是可能在它处重新变赋值的.如下: int i = 0; /* . . . */ i = 20; /*这里重新赋值了*/ 不过有一天我的程序可能需要这样一个变量(暂且称它变量),在声明时就赋一个初始值.之后我的程序在其它任何处都不会再去重新对它赋值.那我又应该怎么办呢?用const . /* . . . */ const int ic =20; /* . . . */ ic = 40; /*这样是不可以的,编译时是无

C语言编程中函数的基本学习教程_C 语言

C 语言中的函数等价于 Fortran 语言中的子程序或函数,也等价于 Pascal 语言中的过程或函数.函数为计算的封装提供了一种简便的方法,此后使用函数时不需要考虑它是如何实现的.使用设计正确的函数,程序员无需考虑功能是如何实现的,而只需知道它具有哪些功能就够了.在 C 语言中可以简单.方便.高效地使用函数.我们经常会看到在定义后仅调用了一次的短函数,这样做可以使代码段更清晰易读. 到目前为止,我们所使用的函数(如 printf.getchar 和 putchar 等)都是函数库中提供的函数