c++:联合和枚举类型区别

Motivation

我这人有一个最大的毛病,学什么东西都总喜欢学个皮毛。

记得大一那会儿我们学C,教材上有几个内容不考,枚举和共用体正是其中之一,我就想当然地觉得没用,也没看。直到前几天在看深度学习框架caffe的时候才回过神来,原来任何东西都是有用的啊!

这篇文章就希望能够对枚举类型enum和共用体union做一个基本的介绍。

一、联合(union)

1.1 union是什么

union,又称联合体或是共用体,是一个能在同一块存储空间中(但非同时)存储不同类型数据的数据类型。也就是说几种成员数据“共用”了同一块存储空间。联合体特别适用于那些彼此互斥,但却又有一定联系的内容。联合体的作用不光是节省存储空间那么简单,更重要的是为数据提供了一个统一的封装和外部访问的接口。C语言编译器保证了union的共用体的长度等于最长的成员的长度。

共用体在使用方法上与结构体有些类似,但切记二者是完全不同的!

1.2 union的定义

union的定义形式为:

union 共用体名 {
    类型名    成员名1;
    类型名    成员名2;
    ... ...
    类型名    成员名n;
};   

下面是一个共用体的例子,在这个例子中,我们定义了共用体类型union group,它有3个成员,分别是int, char, double。由于double成员的长度最大,为8 Bytes,因此,共用体的长度也应为8 Bytes。

// Definition of union
union group {
    int    digit;
    double myfloat;
    char   letter;
};

下面的配图或许能够更好地解释共用体的含义。

这里写图片描述

1.2 union的声明

同结构体类似,union也可以声明为变量、数组、指针等等,如下所示。

union group valA;         // union group联合类型的变量
union group valArray[10]; // 联合类型的数组,长度为10
union group * pA;         // 联合类型的指针

第一个声明创建一个union group类型的变量,编译器将分配足够的空间用以保存可能被描述的最大的需要。此处,成员double所占的空间最大,为8 bytes。第二行创建了一个数据valArray,它包含有10个元素。每个元素大小为8 bytes,第三行声明了一个union group *指针,它可以存放联合体的地址。

1.3 union的初始化和使用

根据C99标准,联合体的初始化与结构体不尽相同。具体地,要初始化联合体,你有三种选择:

  • 可以将一个联合初始化为另一个联合;
  • 可以将一个联合初始化为其第一个成员;
  • 可以指定联合的某个成员进行初始化。

    下面的代码展示了如何进行初始化:

union group valA;         
valA.letter = 'R';
union group valB = valA;  // 将一个联合初始化为另一个联合
union group valC = {88};  // 可以将一个联合初始化为其第一个成员
union group valD = {.myfloat = 118.2};  // 可以指定联合的某个成员进行初始化

下面的代码则展示了如何使用联合体:

valA.digit   = 7;    // 将7存储到valA中,使用2 bytes
valA.myfloat = 2.23; // 将7抹去,存储2.23, 使用8 bytes
valA.letter  = 'T';  // 将2.23抹去,存储字母T,使用1 bytes

点运算符表示正在使用何种数据类型,在同一个时间内只能存储一个值。本例中,即使有足够的空间,也不能存储int型和char型。保存何种数据类型有开发者记忆并管理。建议您在写程序的时候写写注释帮助记忆。

上文中提到了定义指向联合的指针,事实上,我们同样可以使用指针对联合进行操作,如下所示:

pA = & valB;
x  = pA -> digit;

最后给出一个关于共用体union的一个综合的测试例子:

#include <stdio.h>
#include <stdlib.h>


// Definition of union
union group {
    int digit;
    double myfloat;
    char letter;
};

int main() {
    // Declaration of union
    union group valArray[10]; // union for array
    union group * pA;         // union for array

    union group valA;
    valA.letter = 'R';
    union group valB = valA;
    union group valC = {88};
    union group valD = {.myfloat = 118.2};

    // Test the length of union.
    printf("Now, value of `valA` is: %c\n", valA.letter);
    printf("The length of union group is: %d\n", sizeof(union group));

    // Usage of union
    valA.digit = 23;
    printf("Now, value of `valA` is: %d\n", valA.digit);

    // Using pointer
    pA = &valA;
    pA->myfloat = 9.88;
    printf("Now, value of `valA` is: %.4f\n", valA.myfloat);

    return 0;
}

输出结果为: 
Now, value of valA is: R 
The length of union group is: 8 
Now, value of valA is: 23 
Now, value of valA is: 9.8800

二、枚举(enum)

2.1 enum是什么

枚举类型(enumerated type)是一种代表整数常量的数据类型。通过关键字enum,可以创建一个新“类型”并指定它的值。枚举类型的语法与结构体的语法相类似。设计枚举类型的目的在于提高程序的可读性。

例如,可以使用枚举类型指代是或非,使用“1”代表是,使用“0”代表非。又如,可以使用枚举类型代表一个星期的七天。使用整形1~7代表从Monday到Sunday的七天。

值得注意的是,虽然枚举常量是int型的,但枚举常量可以宽松地限定为任何一种整数类型,只要该类型能保存这些枚举常量。例如,上述中星期的取值从1到7,我们就可以使用unsigned char来表示。

2.2 enum的定义

由于枚举类型比较地简单,所以直接看下面的例子:

// Define of the enum
enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};

有必要对上述代码进行一定的说明:

  • 枚举类型的第一个成员默认为0,后续成员的值在前一个成员的基础上自增1;
  • 可以认为设定枚举类型的值,从而使枚举类型在某一个范围内;
  • 枚举类型实际上是#define的包装,因而习惯上在命名时使用大写。

如上述代码,我们定义了enum WEEKDAY类型,用以代表一个星期的七天,我们自行设定了枚举类型的初始值。使得枚举类型的取值范围为:1~7。

2.2 enum的声明

既然枚举类型也是一种数据类型,那么它和基本数据类型一样可以声明为变量。

一般而言,枚举类型的声明分为3种:

  • 枚举类型的定义与变量声明分开;
  • 枚举类型定义的同时进行变量声明;
  • 用typedef给枚举类型起别名

由于枚举类型比较地简单,这里直接给出相关代码:

1.枚举类型的定义与变量声明分开:

// Definition
enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
// Declaration
enum DAY tomorrow; 
enum DAY good_day, bad_day;

2.枚举类型定义的同时进行声明:

// Definition & Declaration
enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} workday;

3.使用typedef给枚举类型起别名:

// Definition
typedef enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} weekday;
// Declaration
weekday today;

特别说明一点,在第三种情况中,使用typedef给枚举类型起别名,是可以将关键字enum后面的“WEEKDAY”省略掉的。

2.3 enum的初始化和使用

本小结将首先介绍枚举类型的初始化问题,然后对使用中一些问题进行说明,最后,通过一个综合实例对枚举类型进行全面的总结。

枚举类型的初始化同样可以使用下述3种方式:

  • 先声明变量,然后再赋值;
  • 声明变量和赋值同时进行;
  • 枚举类型定义、声明、赋初值同时进行。

1.先声明变量,再赋初值。

// Definition
enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
// Declaration
enum DAY tomorrow; 
enum DAY good_day, bad_day;
// Init
tomorrow = WED;
good_day = SAT;
bad_day  = MON;

2.声明和赋值同时进行

// Definition
enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
// Declaration & Init
enum WEEKDAT today = TUE,
         yesterday = MON;

3.类型定义、变量声明、赋值同时进行

// Definition & Declaration & Init
enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} today = TUE, yesterday = MON;

这里需要强调的一点是,尽管方法3看上去比较地简介,但这里还是建议大家定义、声明、赋值能够分开,因为这样会增加程序的可读性。将所有内容混在一起在日后debug的时候可能会很头痛。

下面结合一个具体的例子来讨论枚举类型中强制类型转换的问题。前文曾经提到过,枚举类型实际上是一种指代整形常量的数据类型,那么自然会考虑到,能否使用数学操作呢?答案当时可以的,但是在操作时,需要对类型进行强制类型转换,转换为枚举类型,才能使用,如下所示:

enum WEEKDAY {
      MON=1, TUE, WED, THU, FRI, SAT, SUN
}
enum WEEKDAY today, tomorrow;
today = TUE;
tomorrow = (enum WEEKDAY)(today + 1);  // 类型转换
printf("today is %d, tomorrow is %d\n",today, tomorrow);

如上例所示,我们将“TUE”也就是整型赋值给了today,然后计算today加一后的结果,然而1是int型的,因而我们必须将运算后的结果,显示地转换为枚举类型enum WEEKDAY才能赋值给tomorrow。

输出结果为: 
today is 2, tomorrow is 3

最后我们来通过一个综合实例,对枚举类型做一个总结。

#include<stdio.h>
#include <stdlib.h>

/* Topic: The usage of ``union``
 * Author: LiBin
 * Time: 2015 / 12 / 27
 */

// Definition
typedef enum WEEKDAY {
    MON=1, TUE, WED, THU, FRI, SAT, SUN
} weekday;

// Output the day according to the enum WEEKDAY!
void printDay(weekday day);

int main()
{
    // enum WEEKDAY
    printf("The size of the `enum WEEKDAY` is: %d\n", sizeof(enum WEEKDAY) );
    // Declaration
    weekday today;
    weekday tomorrow;
    // Implementation
    today = TUE;
    tomorrow = (enum WEEKDAY)(today + 1);
    printDay(today);
    printDay(tomorrow);

    return 0;
}

void printDay(weekday day) {
    switch(day) {
    case 1:
        printf("This is Monday.\n");
        break;
    case 2:
        printf("This is Tuesday.\n");
        break;
    case 3:
        printf("This is Wednesday.\n");
        break;
    case 4:
        printf("This is Thursday.\n");
        break;
    case 5:
        printf("This is Friday\n");
        break;
    case 6:
        printf("This is Saturday\n");
        break;
    case 7:
        printf("This is Sunday\n");
        break;
    default:
        printf("Illegal parameter! Please check. quit...\n");
        break;
    }
}

执行后的结果应该为:

The size of the enum WEEKDAY is: 4 
This is Tuesday. 
This is Wednesday.

猜你喜欢

转载自blog.csdn.net/wfei101/article/details/80766884