*关于typedef之前使用过,但一直没有深入研究,趁着这个时候换平台研究下,所与C语言相关的内容没有完全吃透的东西再重新( ̄~ ̄) 嚼一嚼。那就开始吧。
typedef关键字可以用于给数据类型定义一个别名,比如说DL/T645-2007通信协议,大家叫的时候都觉得名字在长了,所以注给他取了个别名645-07,所以只要大家说这个就知道是在讲DL/T645-2007了。
当你定义了一个结构体时,每次创建一个结构体都要使用struct+结构体名的方式,而用了typedef之后,只要一个结构体别名就可以创建了。
struct sttaskParam //本名
{
unsigned char ucParamActive;
unsigned char ucStartActive; //参数F67、F68:定时上报1类数据任务启动/停止设置
unsigned char ucTimeInter; //定时上报周期
unsigned char ucTimeUnit; //定时上报周期单位
unsigned char ucRInter; //曲线数据抽取倍率R
unsigned char ucDUIDNum; //数据单元标识个数n
STDATETIME stStartActive; //发送基准时间
STDATAUNITID stDUID[CON_TASK_DATAUNITNUM]; //数据单元
}STTASKPARAM;
struct sttaskParam Taskparam; //必须使用struct
typedef struct //本名可以省略
{
unsigned char ucParamActive;
unsigned char ucStartActive; //参数F67、F68:定时上报1类数据任务启动/停止设置
unsigned char ucTimeInter; //定时上报周期
unsigned char ucTimeUnit; //定时上报周期单位
unsigned char ucRInter; //曲线数据抽取倍率R
unsigned char ucDUIDNum; //数据单元标识个数n
STDATETIME stStartActive; //发送基准时间
STDATAUNITID stDUID[CON_TASK_DATAUNITNUM]; //数据单元
}STTASKPARAM; //结构体别名
STTASKPARAM stTask1Param[CON_MAX_TASKNUM]; //不使用struct
并且有了别名,本名我都可以不要了(当然你也可以加上)。
虽然说简化写法是一个不错的功能,但却不是一个很必要的功能。那么肯定有别的好处才是。
我们知道C语言定义数据类型的时候只定义了它们之间的关系,但却没有具体定义它们的大小。比如 short 的长度只规定了不大于 int,long的长度不小于 int,int是多大也没确定,所以你会看到51单片机的int大小为两个字节,而在stm32中的长度为 4 字节。所以这个时候有必要使用一个别名来代替具体的数据类型,并且最好这个别名有一定的说明性,所以你会看到stm32库函数有这么一堆申明:
/* exact-width signed integer types */
typedef signed char int8_t;
typedef signed short int int16_t;
typedef signed int int32_t;
typedef signed __int64 int64_t;
/* exact-width unsigned integer types */
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
这样一旦后期换了平台,我就知道怎么根据新平台修改这个定义了,因为这个别名已经有长度、符号信息了。
从51过来的读者可能会说,干嘛要用 typedef,使用 #define (关于#define可以查看#define小节)也能有相同的效果。确实是,但是 #define 严格来说它只是用来替换的,而typedef 是专业的。所以使用 #define 可能一不小心就会给你挖坑了。
#define puchar unsigned char * //puchar被替换的是,之前的部分
puchar pStr1,pStr1; //pStr1是指针,pStr2不是指针
比如上面的,虽然本意是定义两个指针的,但是 #define 比较笨,只会简单替换,所以替换后成了这个样子:
unsigned char * pStr1,pStr1; //pStr1是指针,pStr2不是指针
所以只有一个被定义成了指针,而如果使用 typedef 就没有这个问题。
typedef unsigned char * puchar ; //puchar是别名,
puchar pStr1,pStr1; //pStr1,pStr2都是指针
虽说typedef在取别名上是专业的,但是如果你不熟悉而贸然使用的话也可能会为你挖坑的。下面介绍使用typedef时的一些坑:
##1、const
在和const一起使用的时候,本想定义一个指向的字符为常量的变量指针,但因为typedef的特殊性,不是简单的替换,所以最终的定义的是指向的字符为变量的常量指针。
typedef char * pPCHAR; //定义字符指针的别名
int str(const pPCHAR, const pPCHAR);
/*想定义 指针为变量,指向的字符为常量的 参数
实际上是 指针为常量,指向的字符为变量*/
解决的办法就是在typedef中加const即可:
typedef const char * pPCHAR; //定义字符指针的别名
int str(pPCHAR, pPCHAR); //指针为常量,指向的字符为变量
怎么看哪个可以变,哪个不可以变呢?
就看const修饰哪一个了。如果说const离char近,就是字符不变,如果const离指针名比较近,那就是指针不变,其他类似的,好好理解一下就差不多了。如果实在不理解也没关系,忘记了再回来查一下就行,但是你得知道使用typedef有这么一个坑在就行了。
##2、存储类
typedef 不影响对象的存储特性,但是在语法上它却是一个存储类的关键字,就像 auto、extern、static、register等关键字一样。所以不能和存储类的关键字一起使用:
typedef extern char* pPCHAR1;
typedef static char* pPCHAR2;
typedef auto char* pPCHAR3;
typedef register char* pPCHAR4;
错误的原因就是不能声明多个存储类关键字,typedef 已经申明了存储属性,不允许再有第二个了。这个坑还是不容易跳进去的,毕竟编译器能帮你找出问题来,不用你担心。