40 4 | 128 2 | 128 4 | 0 0
《计算机程序设计》
计算机学院计算机研究所编译系统研究室
~/course
~/course/main.cpp
main.cpp
,随堂编程练习的代码请直接在此文件中编辑编程求解
在指针学习中,曾通过指针将一个内存区以不同类型进行解释,从而实现“动态类型”
dtypemain.cpp
#include <iostream>
#include "dtype.h"
int main() {
int type;
char buffer[sizeof(double)];
int i; double d;
std::cin >> type;
// read in a value and write to buffer according to type
switch (type) { // 0: int, 1: double
case 0: std::cin >> i; writeI(buffer, i); break;
case 1: std::cin >> d; writeD(buffer, d); break;
}
// read out the value from buffer according to type
switch (type) {
case 0: std::cout << readI(buffer) << std::endl; break;
case 1: std::cout << readD(buffer) << std::endl; break;
}
return 0;
}
dtype.h
学习目标
综合使用结构体、联合体与枚举类型,实现动态类型的定义与使用
考考你
试描述下面的数据表示问题有什么共性?
明察秋毫
需要表示的数据是多种类型中的一种!
Number
是联合体类型,number
是联合体变量,其内存区中存储的值
int
值float
值double
值考考你
联合体的成员变量是否可以是任意类型?
“复杂”的联合体类型
明察秋毫
layout.cpp
40 4 | 128 2 | 128 4 | 0 0
明察秋毫
联合体的体积至少为最大成员的体积、对齐至少为最大成员的对齐
考考你
判断程序输出,分析联合体内存布局
layout-quiz.cpp
int main() {
cout << sizeof(Number) << ' ' << alignof(Number) << " | ";
cout << sizeof(NameOrID) << ' ' << alignof(NameOrID) << " | ";
cout << sizeof(Object) << ' ' << alignof(Object) << '\n';
cout << offsetof(Number, i) << ' ' << offsetof(Number, d) << " | ";
cout << offsetof(NameOrID, id) << ' ' << offsetof(NameOrID, name) << " | ";
cout << offsetof(Object, type) << ' ' << offsetof(Object, number) << ' '
<< offsetof(Object, nameOrID) << '\n';
return 0;
}
8 8 | 12 4 | 32 8
0 0 | 0 0 | 0 8 16
code/init.cpp: In function ‘int main()’:
code/init.cpp:11:15: error: conversion from ‘int’ to non-scalar type ‘Number’ requested
11 | Number n3 = 1; // compile error
| ^
code/init.cpp:12:15: error: conversion from ‘double’ to non-scalar type ‘Number’ requested
12 | Number n4 = 1.0; // compile error
| ^~~
code/init.cpp:14:19: error: narrowing conversion of ‘1.0e+0’ from ‘double’ to ‘int’ [-Wnarrowing]
14 | Number n6 = {1.0}; // compile error
| ^
教员箴言
使用指定初始化列表初始化联合体变量!
.
或指针成员运算符->
明察秋毫
访问哪个成员,就按照该成员的类型解释所属的内存!
anonymous.cpp
#include <iostream>
struct Number {
int type;
union {
int i;
float f;
double d;
struct { float r, i; } fc;
struct { double r, i; } dc;
} value;
};
int main() {
Number n1 = {.type = 0, .value.i = 3}; // type==0: int
Number n2 = {.type = 1, .value.f = 3.14f}; // type==1: float
Number n3 = {.type = 2, .value.d = 3.14}; // type==2: double
Number n4 = {.type = 3, .value.fc = {3.14f, 2.71f}};// type==3: float complex
Number n5 = {.type = 4, .value.dc = {3.14, 2.71}}; // type==4: double complex
return 0;
}
考考你
在上一页的例子中,使用整形变量type
实现动态类型识别,有什么缺点?
anonymous.cpp
#include <iostream>
struct Number {
int type;
union {
int i;
float f;
double d;
struct { float r, i; } fc;
struct { double r, i; } dc;
} value;
};
int main() {
Number n1 = {.type = 0, .value.i = 3}; // type==0: int
Number n2 = {.type = 1, .value.f = 3.14f}; // type==1: float
Number n3 = {.type = 2, .value.d = 3.14}; // type==2: double
Number n4 = {.type = 3, .value.fc = {3.14f, 2.71f}};// type==3: float complex
Number n5 = {.type = 4, .value.dc = {3.14, 2.71}}; // type==4: double complex
return 0;
}
注记
C++枚举类型用于表示离散的、非数值的有限数据集
枚举值
#include <iostream>
using namespace std;
enum Season { Spring, Summer, Autumn, Winter };
enum Sex { Male = 'M', Female = 'F' };
enum Weekday { Sun = 1, Mon, Tue, Wed, Thu, Fri, Sat };
int main() {
cout << Spring << ' ' << Summer << ' ' << Autumn << ' ' << Winter << '\n';
cout << Male << ' ' << Female << '\n';
cout << Sun << ' ' << Mon << ' ' << Tue << ' ' << Wed << ' ' << Thu << ' '
<< Fri << ' ' << Sat << '\n';
}
0 1 2 3
77 70
1 2 3 4 5 6 7
enumvar
考考你
可否将超出枚举值范围的整数值转换为枚举类型?如第9行
code/enumvar.cpp: In function ‘int main()’:
code/enumvar.cpp:6:13: error: cannot convert ‘Season’ to ‘Sex’ in initialization
6 | Sex sex = Summer;
| ^~~~~~
| |
| Season
code/enumvar.cpp:7:17: error: invalid conversion from ‘int’ to ‘Weekday’ [-fpermissive]
7 | Weekday Mon = 1;
| ^
| |
| int
测一测
下列有关枚举类型的说法中,正确的有
Number
Number
类型可表示一个int
,或一个double
,或一个单精度复数Complex
表示单精度复数Type
表示数据类型,使用匿名联合存储数据操作 | 函数签名 | 说明 |
---|---|---|
写整数 | void setInt(Number &n, int i) |
|
写浮点数 | void setDouble(Number &n, double d) |
|
写复数 | void setComplex(Number &n, Complex c) |
|
读整数 | int *getInt(Number &n) |
若不是整数,返回nullptr |
读浮点数 | double *getDouble(Number &n) |
若不是整数,返回nullptr |
读复数 | Complex *getComplex(Number &n) |
若不是整数,返回nullptr |
输出 | void print(Number &n) |
格式分别为1 、2.0 、(1.2, 2.3) |
--- config: look: handDrawn themeVariables: fontSize: 20px --- mindmap 联合体与枚举类型 联合体 联合体定义 联合体存储布局 联合体初始化 访问联合体成员 匿名联合 枚举类型 枚举类型定义 枚举值 枚举变量的取值 动态数据类型
学习目标
计算机程序设计