您的位置:首页 > 编程语言 > C语言/C++

深入学习C语言系列(二): #define与typedef

2015-10-05 23:06 393 查看




#define与typedef

先举个例子:

#define PI 3.1415926;

复制代码

上面这行代码的意思是:将3.1415926用PI来代替,后面的代码中凡是要用到3.1415926的地方皆可写作PI。

值得注意的是,define语句是被编译器在“预编译”阶段进行“替换”处理的,也就是说,当我们生成可执行文件的时候,可执行文件里并没有PI这个内容,而统统是3.1415926。

于是#define的作用就是在编程的时候为代码编写提高便利,将“魔数”(纯数字)用一个符号(例如本例中的PI)来代替。这样的好处就是减少了书写工作量,不易出错,并且易于统一修改。

再看一个typedef的例子:

typedef char int8;

复制代码

这个例子的意思是:给关键字char起个“别名”叫做int8。所谓别名,也就是外号的意思。

这样我们就知道了,在后面的代码中,任何一个要使用char的地方,都可以使用int8来代替。

typefdef的主要作用是使得一些比较长的关键字可以用一个较短的“外号”来替代,例如:

typedef unsigned long int uint32;

复制代码

上面这行代码就把unsigned long int给起了个别名,叫做uint32,是不是简洁了许多呢?!这样如果我们要声明一个变量

unsigned long int XX;

复制代码

的话,就只需写为uing32 XX就可以了。

至此,我们已经介绍完了#defind和typedef的作用,很多人认为他们俩作用类似,分不清有什么区别。现在我们来区分一下他们:

1.编译时间不同:#define是在预编译阶段编译的,而typedef是在编译的时候才执行的。

2.#define只是简单的替换,而typedef是为一个原有的关键字起一个“别名”。

①#define经常被用来处理“魔数”问题,例如

#define PI 3.1415926;

复制代码

,而typedef不可以,因为“别名”也是名,要符合命名规则。

②typedef的一个重要的用武之地是给结构体起别名,例如:

struct student

{

char name[16];

int age;

double score;

};

复制代码

可以用typedef处理为:

typedef struct student

{

char name[16];

int age;

double score;

}Stu,*pStu;

复制代码

这样的好处是,以后凡是声明变量时用到形如“

struct student XX;

复制代码

”的地方,都可以简写为

Stu XX;

复制代码

凡是声明变量时用到形如“

struct student *p;

复制代码

”的地方,都可以简写为

pStu p;

复制代码



有人可能会问,用

#define struct student Stu;

复制代码



#define struct student *pStu;

复制代码

不一样可以实现简化功能吗?实际上,不完全是这样的。我们看下面的代码:

struct student

{

char name[16];

int age;

double score;

};

#define struct student *pStu_1;

typedef struct student *pStu_2;

复制代码

这两行代码都实现了“简化代码”的作用,但是简化的效果是不一样的。如果我们写这样一句代码:

pStu_1 A,B,C;

复制代码

那么,只有A是指针变量,B和C都是struct student类型的变量,因为这句代码“反替换”后原型是:

struct student *A,B,C;

复制代码



int X,Y,*Z

复制代码

类似。

而如果我们改用

pStu_2 A,B,C;

复制代码

来声明变量,其结果是A,B,C都是struct student* 类型的指针变量,因为“别名”是“全功能”的。上面这行代码的原型是:

struct student *A,*B,*C;

复制代码

3.数组的问题:

如果我们写一行这样的代码:

typedef int line[16];

复制代码

那么后面如果我们这样来声明一个变量:

line a;

复制代码

那么a就是一个具有16个sizeof(int)大小的变量(或者说内存区域)。因为它的原型是:

int a[16];

复制代码

这其实就是声明了一个数组,a是数组名,亦即该片内存的首地址。这种使用方法常见于声明一个大小固定且连续的内存做“数据缓冲区”的时候。

4.参数问题:

#define是可以带参数的,例如:

#define XX(a,b) myfun(a,b);

复制代码

其中myfun(a,b)是一个函数调用,a,b是传给myfun()函数的参数,以后皆可以用宏定义XX(a,b)来代替这个函数调用了,而且在宏定义里参数(a,b)可以像变量一样为合理的任意值。

有人可能要问:我直接在代码里写myfun(a,b)来调用子函数不就可以了,干嘛要多此一举搞个宏定义呢?答案很简单,因为宏定义不仅能使你的代码变简短,而且它的参数类型是任意的(或者说参数没有类型),这在某些时候很有用!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: