typedef的应用
typedef
是C 语言中用于为现有数据类型指定替代名称的关键字。它主要用于用户定义的数据类型,当数据类型的名称在程序中使用变得稍微复杂时。以下是使用的一般语法
typedef <existing_name> <alias_name>
应用一:结构体别名
typedef也可用于为用户定义的数据类型命名。让我们看看它对结构体的使用。
// ======== old
struct type_name
{
type member1;
type member2;
type member3;
};
struct type_name name;
// ========== 分割线
typedef struct
{
type member1;
type member2;
type member3;
} type_name;
type_name name; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
应用二:类型别名
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。例如:
int* x, y;
通过这个声明语句,我们实际上声明一个类型为int的指针x,而y则任然声明为一个普通int变量。但是如果我们typedef像在上面的例子中使用的那样使用,我们可以在单个语句中声明任意数量的指针。
typedef int* IntPtr;
IntPtr x, y, z;
但是,有一点需要注意的是,类型别名是别名,但不是全等。例如
typedef int* intptr;
const intptr x; // x是一个const pointer,指向int
不等同于:
const int *x; // x是一个指针,指向const int
intptr
是指向 int 的指针。const intptr
是一个const pointer 指向 int, 而不是指向 const int。所以,在 typedef pointer 之后,不能再让它成为content的常量了?即x++
将报错。
其相当于:
int * const x;
在标准库中也有些丑陋的实现,比如 gcc 的typeof 宏:
typedef int* intptr;
intptr dummy;
const typeof(*dummy) *x;
应用三:适配解耦
比如定义一个叫 REAL 的浮点类型,在系统Platform A上,让它表示最高精度的类型为:
typedef long double REAL;
在不支持 long double 的系统Platform B上,改为:
typedef double REAL;
在连 double 都不支持的系统Platform C上,改为:
typedef float REAL;
也就是说,当跨平台时,只要改下 typedef 本身就行,或者使用宏开关控制即可,将对应类型与平台解耦。
#ifdef PlatformA
typedef long double REAL;
#elseif Platform B
typedef double REAL;
#elseif Platform C
typedef float REAL;
#else
typedef void REAL;
#endif
标准库就广泛使用了这个技巧,比如size_t。
应用四:代码灵活性
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举两个例子:
- 原声明一:
void (*b[10]) (void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];
- 原声明二:
doube(*)() (*e)[9];
变量名为e,先替换左边部分,pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny (*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;
理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。
另外,void*
在C语言作为万能指针,因为C中的非强耦合,很多时候利用其强转保持代码的复用性、灵活性, 声明为用户类型和用户指针类型也稍许不同,但本质都计算地址偏移。
#ifdef __cplusplus
extern "C" {
#include <stdio.h>
typedef void (CbkFuncPoint)(int i, int j); // void
void (*CbkFunc)(int i, int j); // void *
typedef void (*CbkFuncVar)(int i, int j); // void *
struct TestStru {
int id;
void *func;
};
void testCbk(int i, int j)
{
printf("TestCbk %d\n", i+j);
}
void testCbk2(int i, int j, int k)
{
printf("TestCbk2 %d\n", i+j);
(void)k;
}
int main()
{
#if 1
CbkFunc = &testCbk;
testCbk(0, 10);
((CbkFuncPoint*)testCbk)(0, 10);
CbkFuncPoint *FuncPoint;
FuncPoint = testCbk;
FuncPoint(0, 10);
CbkFuncVar FuncVar;
FuncVar = &testCbk;
FuncVar(0, 10);
#endif
struct TestStru struvar = {
10, (void *)testCbk
};
(*((CbkFuncPoint*)struvar.func))(10, 20);
((CbkFuncPoint*)struvar.func)(10, 20);
(*((CbkFuncPoint*)testCbk))(30, 40); // (void(*)(int, int))&testCbk
(*((CbkFuncPoint*)testCbk2))(30, 40); // 参数不一致的特殊情况也能强转匹配
void *tt = (void *)testCbk;
((CbkFuncPoint*)tt)(40, 50);
return 0;
}
}
#endif