深入学习C语言系列(二): #define与typedef
2015-10-05 23:06
393 查看
先举个例子:
#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)来调用子函数不就可以了,干嘛要多此一举搞个宏定义呢?答案很简单,因为宏定义不仅能使你的代码变简短,而且它的参数类型是任意的(或者说参数没有类型),这在某些时候很有用!
相关文章推荐
- VC++动态链接库
- C语言深入学习系列+-+字节对齐and内存管理
- iOS开发分分钟搞定C语言 —— 总结
- C语言简单的一些简单例子
- iOS开发分分钟搞定C语言 —— 宏定义和关键字
- c++进阶
- c++进阶
- 10.5做题——全排列(初赛复习)
- iOS开发分分钟搞定C语言 —— 结构体和枚举
- iOS开发分分钟搞定C语言—— 字符串和指针
- C++ 内存相关
- iOS开发分分钟搞定C语言 —— 数组及排序
- iOS开发分分钟搞定C语言 —— 进制
- [C++] c language 23 keywords
- iOS开发分分钟搞定C语言 —— 函数
- c++静态成员
- 玩转Google开源C++单元测试框架Google Test系列(gtest)
- iOS开发分分钟搞定C语言 —— 流程控制
- 黑马程序员——C语言日志——static和extern
- iOS开发分分钟搞定C语言 —— 运算符