关于typedef的用法总结

typedef在C语言中用于创建类型别名,简化结构体声明,增强代码可读性和灵活性。例如,可以为结构体定义别名,减少在声明时的冗余;为复杂类型创建简单别名,方便声明多个指针;在跨平台编程中解耦类型与特定平台的关联;以及通过typedef增强代码的可读性,如在回调函数和指针类型中的应用。此外,typedef还能帮助理解复杂声明的结构。
摘要由CSDN通过智能技术生成

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

参考资料

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值