Usage of typedef and define

本文详细阐述了typedef在C++中的用法及其优势,包括简化代码、方便移植和定义与平台无关的类型,并提供了实例解析复杂声明。同时,文章强调了使用typedef时的陷阱,如与const的正确结合与避免存储类关键字的冲突。

刚接触vc6.0这个IDE的时候,发现MFC里面定义了很多新的变量类型,其实应该说是定义了很多已有类型的别名,刚开始学习的时候确实有点儿不习惯,后来想想为什么要重新定义一些新的类型名称呢?我自认为的好处是:(1)简化代码,使用方便;(2)方便移植。当我们要查找某个新定义的类型具体是什么的时候,一般在调试程序的时候,直接将鼠标放在我们所要查找的新类型的名称上,然后按F12即可以跳转到新类型定义的地方。

所以,我们在写程序的时候,也可以使用这一机制,即,用typedef来定义新的类型名称。下面我总结了一些关于typedef的用法和注意事项(也参考了一些网上的资料):


Part1:关于typedef的用法

我们根据用途来分别介绍一下typedef的相关用法。

 

(1)typedef用于定义一种类型的别名,而不只是简单的宏替换。可以使用这个别名同时声明某一类型的多个对象。

可以看出,在需要大量声明某些类型对象的时候(比如char*),使用typedef的方式更省事。

 

(2)用typedef帮助我们简化代码。
我们知道,在C语言中,一般我们定义一个struct结构体,以及定义一个其对象的方法如下:

而在C++中,我们定义一个结构体对象一般是直接写:结构名 对象名; 即,POINT p1; 为什么可以这样呢?是因为:

简化代码的好处,不只是上面这一点,typedef还可以将一个复杂的声明另起(定义)一个简单的别名。见第(3)点。

 

(3)typedef为复杂的声明定义一个新的简单的别名。
方法是:在原来的声明里逐步用别名替换一部分复杂的声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。
例1:
原声明:int*(*a[5])(int,char*);
//a是一个变量,后面接[],说明是一个数组([]的优先级高于*),前面有一个*,说明是一个指针,即,指针类型的数组。再看,(*a[5])后面有一对()括号,说明这是个函数,即,数组里面存放的是函数指针。这个函数有两个参数,分别是int类型和char*类型,且返回值为int*类型。
按照上面的方法,变量名为a,直接用一个新别名pFun替换a就可以了:
typedef int*(*pFun)(int,char*);
此时我们再想定义一个可以存放5个函数指针的数组,就可以简单地写为:
pFun a[5];   //原声明的最简化版本

例2:
原声明:void(*b[10])(void(*)());
//b是一个变量,后面接[],说明是一个数组([]的优先级高于*),前面有一个*,说明是一个指针,即,指针类型的数组。再看,(*b[10])后面有一对括号,说明这是一个函数,即,数组里面存放的是函数指针。然后我们发现函数的参数列表中,仅有一个参数,且这个参数是一个函数指针,此函数的参数为空,且返回值为void类型。而前面的那个函数的返回值为void类型。
按照上面的方法,变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];

例3:
原声明:doubl(*)()(*e)[9];
//e是一个变量,前面有一个*,说明它是一个指针。再看(*e)的后面是一个[],说明它指向一个数组,这个数组是什么类型呢?前面是一个double(*)(),是一个函数指针,参数为空,返回值为double类型。即,声明了指针e,它指向一个数组,这个数组存放的是double(*)()类型的函数指针。
按照上面的方法,变量名为e,先替换左边部分,pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny (*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;


理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到第一个右圆括号(')')就调转阅读的方向;此括号内分析完就跳出此括号然后分析此括号后面的内容,还是按先右后左的顺序,如此循环,直到整个声明分析完。
举例:
int (*func)(int *p);
首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func[5])(int *);
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。


自己感觉分析复杂声明的方法,有点儿像我们在英语中分析一个so long的定语从句,有很多嵌套,一个定语从句中嵌套若干个定语从句,所以我们一般是,先找到主句,然后再分析从句,一步一步解剖,直至分析完毕。

我们也可以记住2个模式:
type (*)(...)  //函数指针(指向一个函数的指针)
type (*)[]     //数组指针(指向一个数组的指针)


(4)用typedef来定义与平台无关的类型。(方便移植)
比如我们定义一个叫REAL的浮点类型,在目标平台一上,让它表示最高精度的类型为: 
 
在不支持long double的平台二上,改为:

在连double都不支持的平台三上,改为:


也就是说,当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改。
 
标准库就广泛使用了这个技巧,比如size_t类型。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。


Some Pitfalls of Using typedef


[陷阱一]
以前我发过一篇关于const限定符用法的文章,当时特别要求注意,当const和typedef一起使用的时候,很多人会出错!
记住,typedef是为一种类型定义了一个新名字(别名),不同于宏,它不是简单的字符串替换。

typedef定义的别名不能做简单的字符替换,我们应该把它看成是一个很好的封装,即,const修饰的是PSTR,也就是说,修饰的是char*这个整体。而const char* cstr;指明的是,const限定符修饰的是char,而不是char*!所以,const PSTR cstr;  定义的是一个指向char类型的const指针(即,常量指针,必须初始化,且以后指针的方向不能再被改变)。

注意:
const char * cstr;//等价于char const * cstr; (即,const限定符可以放在所修饰类型的前面或者后面,建议,放在后面好理解。)


[陷阱二]
typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性。
typedef static int SINT;   //不可行
编译将失败,会提示“指定了一个以上的存储类”。因为不能在声明中有多个存储类关键字,typedef已经占据了存储类关键字的位置,在

typedef声明中不能用register(或任何其它存储类关键字)。


Part2:关于#define的用法

#define为一宏定义语句,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善、背后一长串”的宏,它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了,但也因此难以发现潜在的错误及其它代码维护问题。

在C语言中,#define主要用于定义一些常量,而在C++中,则建议用const定义常量,因为可以定义自己的类型。(更详细的原因可以查阅《Essential C++》)

下面给出一个用#define写的一个有趣的程序例子,帮助我们理解它的用法:


最后,欢迎对本篇文章内容有不同见解的朋友留言讨论!:)


我把用户空间内对soc的代码发给你,参考后修改这个驱动#include <sys/types.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/ioctl.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include "soc/soc.h" #include "soc/ioctl.h" #include "soc/sysinfo.h" #include "soc/busrw.h" #include "soc/egpio.h" #include "soc/vcxo.h" #define VCXO_1_CLK_IN 80000000 int soc::dev; uint16_t soc::version; uint16_t soc::devcode; uint32_t soc::clk_freq; double soc::clk_MHz; double soc::clk_MHz_div_65536; uint8_t soc::sclk_ratio_prescale; unsigned int soc::peri_base; unsigned int soc::mm_base; bool soc::flag_dma_mapped; unsigned int soc::flags; sysinfo_typedef* soc::sysinfo; euart_typedef* soc::chuart; mcbsp_typedef* soc::mcbsp; sclk_typedef* soc::sclk; busrw_typedef* soc::busrw; trig_typedef* soc::trig; pktdma_typedef* soc::pktdma; pack_typedef* soc::pack; ledspi_typedef* soc::ledspi; systime_typedef* soc::systime; vcxo_typedef* soc::vcxo; euart_typedef* soc::gpsuart; gps_typedef* soc::gps; euart_typedef* soc::pwruart; egpio_typedef* soc::egpio; espi_typedef* soc::espi0; espi_typedef* soc::espi1; espi_typedef* soc::espi2; espi_typedef* soc::espi3; espi_typedef* soc::espi4; espi_typedef* soc::espi5; espi_typedef* soc::espi6; espi_typedef* soc::espi7; espi_typedef* soc::bal_spi0; espi_typedef* soc::bal_spi1; busrw_ex_typedef* soc::busrw_ex; vcxo_typedef* soc::vcxo_1; static int map_peripherals(); static void soc_chk_ver(uint16_t pid, uint8_t var); int soc_init(uint16_t pid, uint8_t var) { soc::flags = 0; soc::dev = open("/dev/dhsoc", O_RDWR); if(soc::dev < 0) { printf(APP_NAME": soc: Cannot open /dev/dhsoc: %s (errno=%d)\n", strerror(errno), errno); return -1; } if(map_peripherals() < 0) { printf(APP_NAME": soc: deinit.\n"); soc_deinit(); return -1; } printf(APP_NAME": About to read sysinfo at 0x%08x\n", soc::peri_base + SYSINFO_OFFSET); soc::version = sysinfo_version(soc::sysinfo); soc::devcode = sysinfo_device(soc::sysinfo); printf(APP_NAME": soc version: 0x%x\n", (uint32_t)soc::version); // printf(APP_NAME": soc devcode: 0x%x\n", (uint32_t)soc::devcode); soc_chk_ver(pid, var); busrw_close(soc::busrw); // Call busrw_close to init channel map RAM sysinfo_set_busrw_type(soc::sysinfo, 0); return 0; } void soc_deinit() { if(soc::peri_base) { munmap((void *)(soc::peri_base), DHSOC_PERI_REGION); soc::peri_base = 0; } if(soc::mm_base) { munmap((void *)(soc::mm_base), DMA_MEM_REGION); soc::mm_base = 0; } if(soc::dev) { close(soc::dev); } } bool soc_clk80m_alt_pll_locked() { return egpio_read_pin(soc::egpio) & EGPIO_IN_CLK80M_ALT_PLL_LOCKED; } static int map_peripherals() { soc::peri_base = (unsigned int) mmap(0, DHSOC_PERI_REGION, PROT_READ | PROT_WRITE, MAP_SHARED, soc::dev, LW_H2F_BASE); printf(APP_NAME": soc: mmap peri_base success.\n"); soc::mm_base = (unsigned int) mmap(0, DMA_MEM_REGION, PROT_READ | PROT_WRITE, MAP_SHARED, soc::dev, DMA_MEM_BASE); printf(APP_NAME": soc: mmap mm_base success.\n"); printf("DEBUG: peri_base = 0x%08x, mm_base = 0x%08x\n", soc::peri_base, soc::mm_base); if( (!soc::peri_base) || (!soc::mm_base) ) { printf(APP_NAME": soc: mmap failed.\n"); return -1; } soc::flag_dma_mapped = true; soc::sysinfo = (sysinfo_typedef *) (soc::peri_base + SYSINFO_OFFSET); soc::chuart = (euart_typedef *) (soc::peri_base + CHUART_OFFSET); soc::mcbsp = (mcbsp_typedef *) (soc::peri_base + MCBSP_OFFSET); soc::sclk = (sclk_typedef *) (soc::peri_base + SCLKCTRL_OFFSET); soc::busrw = (busrw_typedef *) (soc::peri_base + BUSRW_OFFSET); soc::trig = (trig_typedef *) (soc::peri_base + TRIG_OFFSET); soc::pktdma = (pktdma_typedef *) (soc::peri_base + PKTDMA_OFFSET); soc::pack = (pack_typedef *) (soc::peri_base + PACK_OFFSET); soc::ledspi = (ledspi_typedef *) (soc::peri_base + LEDSPI_OFFSET); soc::systime = (systime_typedef *) (soc::peri_base + SYSTIME_OFFSET); soc::vcxo = (vcxo_typedef *) (soc::peri_base + VCXO_OFFSET); soc::gpsuart = (euart_typedef *) (soc::peri_base + GPSUART_OFFSET); soc::gps = (gps_typedef *) (soc::peri_base + GPSSYNC_OFFSET); soc::pwruart = (euart_typedef *) (soc::peri_base + PWRUART_OFFSET); soc::egpio = (egpio_typedef *) (soc::peri_base + EGPIO_OFFSET); soc::espi0 = (espi_typedef *) (soc::peri_base + ESPI0_OFFSET); soc::busrw_ex = (busrw_ex_typedef *)(soc::peri_base + BUSRW_EX_OFFSET); soc::vcxo_1 = (vcxo_typedef *) (soc::peri_base + VCXO_1_OFFSET); soc::espi1 = (espi_typedef *) (soc::peri_base + ESPI1_OFFSET); soc::espi2 = (espi_typedef *) (soc::peri_base + ESPI2_OFFSET); soc::espi3 = (espi_typedef *) (soc::peri_base + ESPI3_OFFSET); soc::espi4 = (espi_typedef *) (soc::peri_base + ESPI4_OFFSET); soc::espi5 = (espi_typedef *) (soc::peri_base + ESPI5_OFFSET); soc::espi6 = (espi_typedef *) (soc::peri_base + ESPI6_OFFSET); soc::espi7 = (espi_typedef *) (soc::peri_base + ESPI7_OFFSET); soc::bal_spi0 = (espi_typedef *) (soc::peri_base + BAL_SPI0_OFFSET); soc::bal_spi1 = (espi_typedef *) (soc::peri_base + BAL_SPI1_OFFSET); printf(APP_NAME": soc: mmap success.\n"); return 0; } static void soc_chk_ver(uint16_t pid, uint8_t var) { // Default SoC configuration soc::clk_freq = SYS_CLK_v1; soc::clk_MHz = (double)soc::clk_freq * 0.000001; soc::clk_MHz_div_65536 = soc::clk_MHz * 0.0000152587890625; soc::sclk_ratio_prescale = 32; if( (pid == 0x5922) && ((var == 'N') || (var == 0)) ) { // Keep default config } else { // soc clock if(soc::version > 3) { soc::clk_freq = SYS_CLK_v4; soc::clk_MHz = (double)soc::clk_freq * 0.000001; soc::clk_MHz_div_65536 = soc::clk_MHz * 0.0000152587890625; } // re-sample ratio prescale if(soc::version > 4) { soc::sclk_ratio_prescale = 1; } // SoC module if(soc::version > 0xC) { soc::flags |= SOC_FLAG_SYSTIME_SUPPORT; } if(soc::version > 0xE) { soc::flags |= SOC_FLAG_GPSSYNC_SUPPORT; soc::flags |= SOC_FLAG_PWRUART_SUPPORT; } if(soc::version > 0x16) { if(soc_clk80m_alt_pll_locked()) { printf("vcxo 20M -> 80M is locked.\n"); } else { printf("vcxo 20M -> 80M is NOT locked.\n"); } soc::flags |= SOC_FLAG_VCXO_1_SUPPORT; soc::vcxo_1->fvcxo_l = (uint16_t)(VCXO_1_CLK_IN - 1); soc::vcxo_1->fvcxo_h = (uint16_t)((VCXO_1_CLK_IN - 1) >> 16); } } printf("\tSoC Sys Time Support: %c\n", (soc::flags & SOC_FLAG_SYSTIME_SUPPORT) ? 'Y' : 'N'); printf("\tSoC GPS Sync Support: %c\n", (soc::flags & SOC_FLAG_GPSSYNC_SUPPORT) ? 'Y' : 'N'); printf("\tSoC PWR UART Support: %c\n", (soc::flags & SOC_FLAG_PWRUART_SUPPORT) ? 'Y' : 'N'); printf("\tSoC VCXO(-1) Support: %c\n", (soc::flags & SOC_FLAG_VCXO_1_SUPPORT ) ? 'Y' : 'N'); } #ifndef SOC_H #define SOC_H #include "systype.h" /* system clock in HZ AND system clock in ns */ //#define SYS_CLK_HZ 51200000 //#define SYS_CLK_NS 20 // 19.53125 #define SYS_CLK_v1 51200000 #define SYS_CLK_v4 102400000 #define MCLK_20M (20 * 1000 * 1000) /* SoC peripheral/mm phy base & region */ #define LW_H2F_BASE 0xFF200000 #define DHSOC_PERI_REGION 4096 #define DMA_MEM_BASE (512 * 1024 * 1024) #define DMA_MEM_REGION (512 * 1024 * 1024) /* peripheral addr */ #define SYSINFO_OFFSET 0x00 #define CHUART_OFFSET 0x20 #define MCBSP_OFFSET 0x40 #define SCLKCTRL_OFFSET 0x60 #define BUSRW_OFFSET 0x80 #define TRIG_OFFSET 0xA0 #define PKTDMA_OFFSET 0xC0 #define PACK_OFFSET 0xE0 #define LEDSPI_OFFSET 0x100 #define SYSTIME_OFFSET 0x120 #define VCXO_OFFSET 0x140 #define GPSUART_OFFSET 0x160 #define GPSSYNC_OFFSET 0x180 #define PWRUART_OFFSET 0x1A0 #define EGPIO_OFFSET 0x1C0 #define ESPI0_OFFSET 0x1E0 #define BUSRW_EX_OFFSET 0x200 #define VCXO_1_OFFSET 0x220 #define ESPI1_OFFSET 0x240 #define ESPI2_OFFSET 0x260 #define ESPI3_OFFSET 0x280 #define ESPI4_OFFSET 0x2A0 #define ESPI5_OFFSET 0x2C0 #define ESPI6_OFFSET 0x2E0 #define ESPI7_OFFSET 0x300 #define BAL_SPI0_OFFSET 0x320 #define BAL_SPI1_OFFSET 0x340 #define EGPIO_IN_CLK80M_ALT_PLL_LOCKED (1 << 0) struct sysinfo_typedef; struct euart_typedef; struct mcbsp_typedef; struct sclk_typedef; struct busrw_typedef; struct trig_typedef; struct pktdma_typedef; struct pack_typedef; struct ledspi_typedef; struct systime_typedef; struct vcxo_typedef; struct gps_typedef; struct egpio_typedef; struct espi_typedef; struct busrw_ex_typedef; struct soc { static int dev; // my device static uint16_t version; // version static uint16_t devcode; // device code static uint32_t clk_freq; // system clock frequency static double clk_MHz; // system clock frequency in MHz static double clk_MHz_div_65536; // for systime usage static uint8_t sclk_ratio_prescale;// resample ratio prescale static unsigned int peri_base; // peri mmap base static unsigned int mm_base; // mm mmap base static uint32_t flags; // some flag static bool flag_dma_mapped; // dma mapped in driver static sysinfo_typedef *sysinfo; // PERI: system info static euart_typedef *chuart; // PERI: channel uart static mcbsp_typedef *mcbsp; // PERI: mcbsp static sclk_typedef *sclk; // PERI: sclkctrl static busrw_typedef *busrw; // PERI: busrw static trig_typedef *trig; // PERI: trig static pktdma_typedef *pktdma; // PERI: pktdma static pack_typedef *pack; // PERI: pack static ledspi_typedef *ledspi; // PERI: ledspi static systime_typedef *systime; // PERI: systime static vcxo_typedef *vcxo; // PERI: vcxo 0 static euart_typedef *gpsuart; // PERI: gps uart static gps_typedef *gps; // PERI: gps static euart_typedef *pwruart; // PERI: pwr uart static egpio_typedef *egpio; // PERI: egpio static espi_typedef *espi0; // PERI: espi static busrw_ex_typedef *busrw_ex; // PERI: busrw_ex static vcxo_typedef *vcxo_1; // PERI: vcxo 1 static espi_typedef *espi1; // PERI: espi static espi_typedef *espi2; // PERI: espi static espi_typedef *espi3; // PERI: espi static espi_typedef *espi4; // PERI: espi static espi_typedef *espi5; // PERI: espi static espi_typedef *espi6; // PERI: espi static espi_typedef *espi7; // PERI: espi static espi_typedef *bal_spi0; // PERI: espi static espi_typedef *bal_spi1; // PERI: espi }; #define SOC_FLAG_SYSTIME_SUPPORT (1 << 0) #define SOC_FLAG_GPSSYNC_SUPPORT (1 << 1) #define SOC_FLAG_PWRUART_SUPPORT (1 << 2) #define SOC_FLAG_VCXO_1_SUPPORT (1 << 3) int soc_init(uint16_t pid = 0x5922, uint8_t var = 'N'); void soc_deinit(void); bool soc_clk80m_alt_pll_locked(void); #endif // SOC_H #ifndef SOC_IOCTL_H #define SOC_IOCTL_H #define DHSOC_IOCTL_MAGIC 0x44 #define DHSOC_IOCTL_WXFERRST _IO(DHSOC_IOCTL_MAGIC, 0) #define DHSOC_IOCTL_GETWXFER _IO(DHSOC_IOCTL_MAGIC, 1) #define DHSOC_IOCTL_USER0CLK _IOW(DHSOC_IOCTL_MAGIC, 5, int) #define DHSOC_IOCTL_INVWXFER _IO(DHSOC_IOCTL_MAGIC, 6) #endif // SOC_IOCTL_H
10-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值