【C进阶】之数据类型起别名( typedef )

1 回顾定义定义的数据类型

// 基本的数据类型
int m_i;
unsigned int m_ui;

// 数组
short m_arr1[2];
unsigned int m_arr2[2][2];

// 指针
int *p;
int **pp;

// 指针数组/数组指针
int *p_arr[2];
int (*arr_p)[2];

// 函数指针
int (*func_p)(int, int);

// 函数指针数组
int (*func_p_arr[2])(int, int);

2 定义变量的数据类型

将变量名去除,剩余的就是你定义变量的数据类型

// 基本的数据类型
int ;
unsigned int ;

// 数组
short [2];
unsigned int [2][2];

// 指针
int *;
int **;

// 指针数组/数组指针
int *[2];
int (*)[2];

// 函数指针
int (*)(int, int);

// 函数指针数组
int (*[2])(int, int);

3 使用新的数据类型定义变量

将typedef写到定义变量的前边,此时变量名就是你的新定义的数据类型,可以使用新的数据类型定义变量

typedef写到定义变量的前边,此时变量名就是你的新定义的数据类型,可以使用新的数据类型定义变量,

// 基本的数据类型
typedef int myint32_t;    // myint32_t是使用typedef对int类型起别名
typedef unsigned int myuint32_t;  // myuint32_t是使用typedef对unsigned int类型起别名

// 数组
typedef short m_arr1_t[2];    // m_arr1_t是使用typedef对short [2]类型起别名
typedef unsigned int m_arr2_t[2][2];  // m_arr12_t是使用typedef对unsigned int [2][2]类型起别名

// 指针
typedef int *p_t;  // p_t是使用typedef对int *类型起别名
typedef int **pp_t;// pp_t是使用typedef对int **类型起别名

// 指针数组/数组指针
typedef int *p_arr_t[2];   // p_arr_t是使用typedef对int *[2]类型起别名
typedef int (*arr_p_t)[2]; // arr_p_t是使用typedef对int (*)[2]类型起别名

// 函数指针
typedef int (*func_p_t)(int, int);  // func_p_t是使用typedef对int (*)(int, int)类型起别名

// 函数指针数组
typedef int (*func_p_arr_t[2])(int, int); 
// func_p_arr_t是使用typedef对int (*[2])(int, int)类型起别名

使用tppedef对数据类型起别名之后,使用别名定义变量和使用本身代表的类型定义变量一样一样。

4 参考案例

#include <stdio.h>

// 使用typedef对数据类型起别名

// 基本的数据类型
typedef int myint32_t;           // myint32_t是使用typedef对int类型起别名
typedef unsigned int myuint32_t; // myuint32_t是使用typedef对unsigned int类型起别名

// 数组
typedef short m_arr1_t[2];           // m_arr1_t是使用typedef对short [2]类型起别名
typedef unsigned int m_arr2_t[2][2]; // m_arr12_t是使用typedef对unsigned int [2][2]类型起别名

// 指针
typedef int *p_t;   // p_t是使用typedef对int *类型起别名
typedef int **pp_t; // pp_t是使用typedef对int **类型起别名

// 指针数组/数组指针
typedef int *p_arr_t[2];   // p_arr_t是使用typedef对int *[2]类型起别名
typedef int (*arr_p_t)[2]; // arr_p_t是使用typedef对int (*)[2]类型起别名

// 函数指针
typedef int (*func_p_t)(int, int); // func_p_t是使用typedef对int (*)(int, int)类型起别名

// 函数指针数组
typedef int (*func_p_arr_t[2])(int, int);
// func_p_arr_t是使用typedef对int (*[2])(int, int)类型起别名

int add(int a, int b)
{
    return a + b;
}
int sub(int a, int b)
{
    return a - b;
}
int main(int argc, const char *argv[])
{
    /*your code*/
    // 基本类型  ----> 比较常见
    myint32_t a = 1000; // 等价于 int a = 1000;

    // 数组 ---> 基本不用
    m_arr1_t arr1 = {100, 200}; // 等价于short arr1[2]={100,200};
    m_arr2_t arr2 = {{100, 200}, {300, 400}};
    // 等价于 unsigned int arr2[2][2] = {{100,200},{300,400}};

    // 指针 ----> 基本不用
    p_t p = &a;   // 等价于int *p = &a;
    pp_t pp = &p; // 等价于 int **p = &p;

    // 指针数组/数组指针  ----> 偶尔使用
    p_arr_t p_arr = {&a, &a}; // 等价于 int *p_arr[2] = {&a, &a};
    int arr[2][2] = {{100, 200}, {300, 400}};
    arr_p_t arr_p = arr; // 等价于 int (*arr_p)[2] = arr;

    // 函数指针  ----> 经常使用
    func_p_t cal_p = add;  // 等价于 add;int (*cal_p)(int, int) =
    /*
        int calculator(int x, int y, int (*cal_p)(int,int))
        {
            return cal_p(x,y);
        }

        使用函数指针类型的别名:
        int calculator(int x, int y, func_p_t cal_p)
        {
            return cal_p(x,y);
        }
    */

    func_p_arr_t func_p_arr = {add,sub}; 
        // 等价于int (*func_p_arr[2])(int, int) = {add,sub};
    return 0;
}

5 typedef和#define的区别

  1. #define宏定义对数据类型起别名在预处理阶段展开;
    typedef对数据类型起别名参与到了编译的阶段;

  2. 使用typedef对数据类型起别名相当于重新定义了一个新的数据类型;
    宏定义就是在预处理阶段进行替换。

  3. 推荐使用typedef对数据类型起别名定义新的数据类型。

    #define  p_t   int *
    p_t p, q;  // int *p, q;   // p是int*类型,q是int类型。
    
    typedef int *p_t;
     p_t p, q;  // int *p, *q;   // p和q都是int*类型
    
  4. 宏定义的结尾不允许出现分号,typedef的结尾必须加分号。

6 typedef的陷阱

陷阱一:

记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如先定义:

typedef   char*   PSTR;

然后:

int   mystrcmp(const   PSTR,   const   PSTR);

const PSTR实际上相当于const char*吗?

不是的,它实际上相当于char* const。

原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。

简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。

陷阱二:

typedef在语法上是一个存储类的关键字(如auto、extern、static、register等一样),虽然它并不真正影响对象的存储特性,如:

typedef   static   int   INT2;   //不可行

编译将失败,会提示“指定了一个以上的存储类”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程远泊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值