结构的数据成员各自占用一块内存空间, 它们形成一个整体, 所占空间是全部成员所占空间的总和。联合与此不同, 它的数据成员重叠挤占同一段内存空间, 有点像"一套班子, 多块招牌", 它们形成的整体, 所占空间取成员中占用空间最大者。下图表示了结构和联合与区别:
struct A { |
| 结构A拥有2个成员: | |||||||||||||||
union B { |
| 联合B拥有2个成员: |
在程序设计中, 联合一般用于把同一段内存空间, 根据不同的情况存储不同类型的数据。下面以几何图形为例说明结构和联合的用法。
对于点, 需要保存该点的横坐标x和纵坐标y; 对于直线, 需要保存直线方程ax + by + c = 0的三个系数; 对于矩形, 需要保存两个点 —— 左上角p1和右下角p2的坐标; 对于圆, 需要保存圆心点center的坐标和半径radius等, 下面是点、线、矩形和圆的结构定义:
POINT结构表示点, 它有两个成员, 分别是点的横坐标x(实数)和纵坐标y(实数):
struct POINT { // 点(16字节) |
|
LINE结构表示直线, 它有三个成员, 分别是直线方程的三个系数(实数):
struct LINE { // 线(24字节) |
|
RECT结构表示矩形, 它有两个成员, 分别是左上角和右下角的点(POINT结构):
struct RECT { // 矩形(32字节) |
|
CIRCLE结构表示圆, 它有两个成员, 分别表示圆心点(POINT结构)和半径(实数):
struct CIRCLE { // 圆(24字节) |
|
对于一个几何图形, 它要么是点, 要么是直线, 要么是矩形, 要么是圆, ...。它不可能既是点, 又是线, 所以只需要用一套内存空间来表示即可。这里可以用联合来表示它:
union SHAPE { // 几何图形(32字节) |
|
虽然从理论上说可以这么做, 但实际使用时却不方便, 因为我们并不清楚这个联合现在到底表示的是什么! 下面是改进的方案, 增设一个标记成员来识辨现在的图形到底是什么! 我们当然可以用编号来表示, 比如: 0 - 表示点, 1 - 表示直线, 2 - 表示矩形, 3 - 表示圆, ...。为了方便, 使用枚举来代替编码, 更直观:
enum SHAPE_TAG {point, line, rect, circle}; // 图形标识类(枚举) |
SHAPE_TAG是枚举类型名, 该类型可取的值有: point, line, rect, circle, 这四个单词分别表示整数0, 1, 2, 3, 用来表示图形类别编号。下面是几何图形的结构定义, 在结构中嵌套了一个无名的联合:
struct SHAPE { // 几何图形结构(36字节) |
|
在几何图形结构里, 有两个成员, 一个是图形标记(枚举, 4字节), 另一个是一个图形联合体(32字节), 它要么是点p(16字节), 要么是直线l(24字节), 要么是矩形r(32字节), 要么是圆c(24字节)。
C++除对结构(struct)进行了扩充以外, 还对联合(union)进行了扩充。在联合中, 不仅可以包含数据成员, 还可以包含成员函数, 和结构中的成员函数相同。
下面来研究一下CPU内部实数的表示方法。整数的表示方法大家都比较熟悉: 有符号的整数在大多数机器里, 都采用补码来表示。而实数的表示方法却比较复杂, 从理论上说, 实数用科学计数法表示。例如:
5.125 = (101.001)2 = (1.01001 × 1010)2
单精度实数(32位)的存储格式为:
符号 | 1位 | 0 - 表示正数, 1 - 表示负数 |
阶码 | 8位 | 用移码表示的指数, 即: 指数 + 增量(127), 10 + 1111111 = 10000001 |
尾数 | 23位 | 小数部分(不含小数点前的1): 01001000000000000000000 |
一般移码是将原码最高位求反, 即00000010的移码为10000010, 相当于增加128; 而Intel的增量为127。小数点前的数字1是有效数字, 应该保存它, 但由于非零二进制实数小数点前的数字只可能是1, Intel的为了节省存储空间, 没有保留这个1, 做计算时将它还原出来, 计算完毕又去掉它。对于特殊的实数0, 则以32位全0数码来表示。
符号 | 阶码 | 尾数 | ||||||||||||||||||||||||||||||||
|
|
|
即: 5.125在机内的32位编码是0100 0000 1010 0100 0000 0000 0000 0000, 用十六进制数书写则是: 40a40000。
下面是一个小程序, 从键盘输入实数, 然后在屏幕上输出该实数的十六进制编码; 或者从键盘输入编码, 然后在屏幕上显示对应的该实数。要实现这个功能, 就必须把4个字节的内存空间, 时而看成是单精度实数, 时而看成是无符号整数, 这正是联合的含义。程序如下:
FLOAT.H
#ifndef _FLOAT_H_ union FLOAT { #endif |
FLOAT.CPP
#include <iostream> #include "float.h" void FLOAT::InputValue() { void FLOAT::OutputValue() const { void FLOAT::InputCode() { void FLOAT::OutputCode() const { |
MAIN.CPP
#include <iostream> using namespace std; #include "float.h" int main() { |
程序运行的结果如下:
请输入实数值: 5.125 |