类型别名
随着多种数据类型的引入,使得我们设计程序时有了更加合理的选择,比如为了防止越界,对两个unsigned int的相加,可以使用unsigned long long来存储结果,如:
unsigned long long sum(unsigned int v1, unsigned int v2);
这些冗长的类型需要更多的输入负担。通过使用typedef声明,可以为现有类型创建一个新的名字(别名),使得复杂的类型声明变得简洁易用。如:
typedef unsigned long long uint64; // 创建 unsigned long long 的类型别名 uint64
typedef unsigned int uint; // 创建 unsigned int 的类型别名 uint
uint64 sum(uint v1, uint v2); // 使用类型别名的函数声明
typedef并不是定义了一个新的类型,只是创建了一个类型的别名。
系数数据类型
通过使用typedef还可以用于定义与平台无关的类型。假如我们正在开发一组用于不同系统的图形计算函数,由于每种系统对于浮点数的支持程度不一样,为此我们需要一个实数类型real,以掩盖这些浮点类型之间的差异,这时可以使用typedef来实现这一点。
#ifdef SYSTEM_A
typedef float real; // 系统A使用float类型来实现real
#endif
#ifdef SYSTEM_B
typedef double real; // 系统B使用double类型来实现real
#endif
#ifdef SYSTEM_C
typedef int real; // 系统C使用int类型来实现real
#endif
void foo(real r1, real r2);
void bar(real r1, real r2);
你可能没有留意到,函数strlen()的返回值不是int类型,也不能说是unsigned int类型,而是与系统相关的size_t类型。
#ifdef _WIN64
typedef unsigned __int64 size_t;
typedef __int64 ptrdiff_t;
typedef __int64 intptr_t;
#else
typedef unsigned int size_t;
typedef int ptrdiff_t;
typedef int intptr_t;
#endif
size_t strlen(char const *str);
这种以_t结尾的数据类型被称为基本系统数据类型。它们通常以typedef声明,目的是阻止程序使用专门的数据类型(int,short...)来表达特定系统的每个实现所要求的数据类型。因为这些类型在不同的环境中,它们的定义可能是不同的,即使用typedef掩盖了它们在不同平台下的差异性。考虑到可移植性,程序应该优先使用这些类型。有很多这种数据类型定义在其他头文件中,如<sys/types.h>中,下表列出了常见的基本系统数据类型。
| 类型 | 说明 |
|---|---|
| size_t | 对象(例如字符串)长度(不带符号的) |
| ptrdiff_t | 两个指针相减的结果(带符号的) |
| intptr_t | 存放指针地址(不带符的) |
| errno_t | 存放错误码(带符号的) |
| time_t | 时间戳 |
| wchar_t | 能表示所有不同的字符码 |
结构体别名
为结构创建别名是一项必备技能,为此我们详细介绍一下,这里我们从struct Point类型开始。
struct Point
{
int x;
int y;
};
void print(struct Point p);
float distance(struct Point *p1, struct Point *p2);
首先创建结构体类型及其指针类型的别名,然后使用这些别名创建变量。
typedef struct Point POINT; // 为类型 struct Point 声明别名 POINT
typedef struct Point* PPOINT; // 为类型 struct Point* 声明别名 PPOINT
POINT p1, p2; // 定义两个 struct Point 变量
PPOINT x, y; // 定义两个 struct Point* 变量(两个指针变量)
这里创建的struct point指针类型别名PPOINT,使得后继依赖此别名定义的变量都是指针类型,这有别于直接使用类型名称创建变量。
struct Point* x, // x 的类型是 struct Point*
y; // y 的类型是 struct Point
通过使用别名,print与distance函数可以改写为:
void print(POINT p);
float distance(PPOINT p1, PPOINT p2);
我们也可以在定义结构体类型的时候直接定义别名,如:
typedef struct Point
{
int x;
int y;
} POINT, *PPOINT, *LPPOINT;
三个类型别名POINT、PPOINT、LPPOINT之间用逗号分隔;这等同于下面的定义,注意:后两者类型都是struct Point*。
typedef struct Point POINT;
typedef struct Point* PPOINT;
typedef struct Point* LPPOINT;
在声明结构体类型时,可以省略其名称,对于这种匿名结构体,可以提供别名以用于在程序中引用此类型。
typedef struct // 这里没有名称
{
int x;
int y;
} POINT, *PPOINT, *LPPOINT;
当然,你也可以创建名称与结构体名称相同的别名,但并不建议这么做。
typedef struct PAIR
{
int x;
int y;
} PAIR;
使用typedef创建别名的规则同样适用于枚举类型。
typedef enum
{
White, Black, Yellow, Green, Blue, Red,
} COLOR, *PCOLOR;
void foo(COLOR value, PCOLOR p);
从行为上感觉typedef和#define很相似,但它们仍有不同之处:
- typedef由编译器解释,#define是预处理指令,由预处理器执行。
- typedef给出的符号名称仅限于对类型,而不是对值。
typedef int INT; // 正确
typedef 3 COUNT; // 错误
#define INT int // 正确,但不建议如此
#define COUNT 3 // 正确
最后,示例程序演示了POINT别名类型的使用。
#include <stdio.h>
#include <math.h>
typedef struct Point
{
int x;
int y;
} POINT, *PPOINT;
float distance(PPOINT p1, PPOINT p2)
{
float x = p1->x - p2->x;
float y = p1->y - p2->y;
return sqrtf(x * x + y * y);
}
int main()
{
POINT p1 = {2, 5}, p2 = {9, 7};
printf("The distance between p1 and p2: %.4f", distance(&p1, &p2));
return 0;
}

数组别名
我们先来看两个数组的定义:
float vec3[3];
int matrix3[3][3];
它们的类型分别是:
float[3];
int[3][3];
你可能认为它们的类型别名是这样子:
typedef float[3] vec3;
typedef int[3][3] matrix3;
不幸的是,这是错误的!为数组类型定义别名,只需要在变量定义的前面加上typedef即可,之前的变量名就是新类型名。
typedef float vec3[3]; // 为 float[3] 定义别名 vec3
typedef int matrix3[3][3]; // 为 int[3][3] 定义别名 matrix3
示例展示了数组别名的应用。
#include <stdio.h>
typedef float vec3[3];
typedef int matrix3[3][3];
void print_vec3(vec3 v)
{
printf("%.1f, %.1f, %.1f\n", v[0], v[1], v[2]);
}
void print_matrix3(matrix3 m)
{
for (int i = 0; i < 3; i++, printf("\n"))
{
for (int j = 0; j < 3; j++)
printf("%d ", m[i][j]);
}
}
int main()
{
vec3 v1 = { -3.0f, 0.0f, 2.5f };
matrix3 m33 = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
printf("================= vec3\n");
print_vec3(v1);
printf("\n================= matrix3:\n");
print_matrix3(m33);
return 0;
}

陕公网安备61011202001108号