C语言之类型定义(typedef)

typedef讲解


typedef关键字的作用是可以用于给数据类型定义一个别名

举个例子,比如说你的名字叫 列夫·尼古拉耶维奇·托尔斯泰 ,我嫌弃这个名字太长了,所以给你取一个别名,叫 托尔斯泰 ,以后我叫 托尔斯泰 的时候你就知道在叫你了。

下面对 typedef 几种用法进行讲解:

1、typedef创建结构体别名

当你定义了一个结构体时,每次创建一个结构体都要使用struct+结构体名的方式,而用了typedef之后,只要一个结构体别名就可以创建了。

struct app_configure {                   //本名
	unsigned char name;
	unsigned char size;
	unsigned char color;
};

struct app_configure app1; 				//必须使用struct
struct app_configure app2;

typedef创建结构体别名

typedef struct app_configure {			
	unsigned char name;
	unsigned char size;
	unsigned char color;
} App_Config;							//别名

App_Config app1;						//不需要用struct
App_config app2; 

此外,用typedef 创建结构体别名时,可以省略本名

typedef struct  {						//省略本名
	unsigned char name;
	unsigned char size;
	unsigned char color;
} App_Config;							//别名

App_Config app1;						//不需要用struct
App_config app2; 
2、typedef创建数据类型的别名

我们知道C语言定义数据类型的时候只定义了它们之间的关系,但却没有具体定义它们的大小。比如 short 的长度只规定了不大于 int,long的长度不小于 int,int是多大也没确定,所以你会看到51单片机的int大小为两个字节,而在stm32中的长度为 4 字节。所以这个时候有必要使用一个别名来代替具体的数据类型,并且最好这个别名有一定的说明性:

typedef signed char					int8_t;
typedef signed short int			int16_t;
typedef signed int					int32_t;

typedef unsigned char				uint8_t;
typedef unsigned short int			uint16_t;
typedef unsigned int				uint32_t;

这样做的好处时代码移植后,我就知道怎么根据新平台修改这个定义了,因为这个别名已经有长度、符号信息了。
从这个角度来看typedef和使用#define是有相同的效果。那么为什么还用使用typedef,确实两者功能类似, 但是#define 严格来说它只是用来替换的,而typedef 是专业的。所以使用 #define 可能一不小心就会给你挖坑了。

#define pCHAR char*
pCHAR   pStr1,pStr2;   	//pStr1 是指针,而pStr2不是

上面这个例子中,由于#define只是进行简单的替换,所以实际上的形式是这个样子的。

char * pStr1, pStr2; 	//pStr1是指针, 而pStr2是char 变量

而如果使用typedef就没有这个问题。

typedef char* pCHAR;		//pCHAR是别名
pCHAR   pStr1, pStr2;		//pStr1, pStr2都是指针

3、注意项:

虽说typedef在取别名上是专业的,但是如果你不熟悉而贸然使用的话也可能会为你挖坑的。下面介绍使用typedef时的一些坑:
1、Const

在和const一起使用的时候,本想定义一个指向的字符为常量的变量指针,但因为typedef的特殊性,不是简单的替换,所以最终的定义的是指向的字符为变量的常量指针。

typedef char* pCHAR;				//定义char指针的别名
int func(const pCHAR, const pCHAR);	//想定义: 指针为变量,指向的字符为常量
									//实际: 指针为常量,指向的字符为变量

解决的办法就是在typedef中加const即可:

typedef const char* pCHAR;			//定义char指针的别名
int func( pCHAR,  pCHAR);			//指针为变量,指向的字符为常量
											

拓展:

const char * const pString1 = "char const, point const";  //指针为常量,指向的字符为常量
char const * const pString1 = "char const, point const";  //指针为常量,指向的字符为常量
char* const pString1	    = "char volatile, point const"; //指针为变量,指向的字符为常量
const char* pString1	    = "char const, point volatile"; //指针为变量,指向的字符为常量
char* pString1	    	    = "char volatile, point volatile";//指针为变量,指向的字符为变量

2、其余出错提示
typedef 不影响对象的存储特性,但是在语法上它却是一个存储类的关键字,就像 auto、extern、static、register等关键字一样。所以不能和存储类的关键字一起使用:
以下都是错的

typedef extern	 char* pCHAR;
typedef static 	 char* pCHAR;
typedef auto  	 char* pCHAR;
typedef register char* pCHAR;

4、 typedef 定义函数指针

typedef  void (*pfun)(void);         // pfun 类型是 void(*)(void)

pfun main;                          // 定义一个函数:void (*main)(void);

下面可以介绍一个经典的函数指针的应用。

#include<stdio.h>

typedef int (*FP_CALC)(int, int);

//注意这里不是函数声明而是函数定义,它是一个地址,你可以直接输出add看看

int add(int a, int b)

{
      return a + b;
}

int sub(int a, int b)

{
      return a - b;
}

int mul(int a, int b)

{
      return a * b;
}

int div(int a, int b)

{
      return b? a/b : -1;
}


//定义一个函数,参数为op,返回一个指针。该指针类型为 拥有两个int参数、

//返回类型为int 的函数指针。它的作用是根据操作符返回相应函数的地址

FP_CALC calc_func(char op)

{
      switch (op)

      {
           case '+' : return add;   // 返回函数的地址

           case '-' : return sub;

           case '*' : return mul;

           case '/' : return div;

           default:

                 return NULL;
      }

      return NULL;
}


//s_calc_func为函数,它的参数是 op,返回值为一个拥有两个int参数、返回类型为int 的函数指针

int (*s_calc_func(char op)) (int, int)

{
      return calc_func(op);
}

//最终用户直接调用的函数,该函数接收两个int整数,和一个算术运算符,返回两数的运算结果

int calc(int a, int b, char op)

{
      FP_CALC fp = calc_func(op);       // 根据预算符得到各种运算的函数的地址

      int (*s_fp)(int, int) = s_calc_func(op);  // 用于测试

     // ASSERT(fp == s_fp);                          // 可以断言这俩是相等的

      if (fp){
          return fp(a, b);  //根据上一步得到的函数的地址调用相应函数,并返回结果
      }

      else{
          return -1;
      }
}

void main()

{

      int a = 100, b = 20;

      printf("calc(%d, %d, %c) = %d\n", a, b, '+', calc(a, b, '+'));

      printf("calc(%d, %d, %c) = %d\n", a, b, '-', calc(a, b, '-'));

      printf("calc(%d, %d, %c) = %d\n", a, b, '*', calc(a, b, '*'));

      printf("calc(%d, %d, %c) = %d\n", a, b, '/', calc(a, b, '/'));

}

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言中,可以使用typedef关键字来定义自己习惯的数据类型名称。这样可以简化代码并增加可读性。例如,可以使用typedef定义一个自定义的数据类型名称,比如BOOL类型,可以将其定义为int类型,并使用#define定义True为1。这样,在代码中就可以直接使用BOOL作为数据类型,并赋值为True或False。另外,结构体也可以使用typedef定义,这样在声明结构体变量时就不需要再加上struct关键字了。例如,可以使用typedef定义一个结构体类型为lept_value,然后在声明结构体变量时就可以直接使用lept_value而不需要加上struct关键字。结构体变量在赋值的同时也可以对结构体中的变量进行赋值。例如,在定义一个结构体Dog时,可以在声明结构体变量dog1时同时对其进行赋值,如dog1={4,'m'}。这样可以方便地初始化结构体变量的值。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [C语言中结构体用到的typedef](https://blog.csdn.net/weixin_44477424/article/details/122796704)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C语言——结构体与typedef](https://blog.csdn.net/fmj2801876977/article/details/129068033)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值