宏定义
因为许多程序需要变量能存储真值或假值,所以C语言缺少适当的布尔类型可能会很麻烦。一直采用模拟布尔型变量的方法来解决麻烦,这种模拟的方法是先声明int型变量,然后将其赋值0或1。
int flag;
flag = 0;
...
flag = 1;
虽然这种方法可行,但是对于程序的可读性没有多大的贡献,因为没有明确地表示flag的赋值只能是布尔值,并且也没明确指出0和1表示假和真。
为了使程序更加便于理解,一个好的方法是类似于TRUE和FALSE这样的名字来定义宏。
#define TRUE 1
#define FALSE 2
现在对flag的赋值有了更加自然的形式。
flag = FALSE;
...
flag = TRUE;
为了判断flag是否为真,可以写成
if(flag == TRUE)
...
或者只写成
if(flag)
...
为了判断flag是否为假,可以写成
if(flag == FALSE)
...
或者只写成
if(!flag)
...
为了进一步实现这个想法,甚至可以定义用作类型的宏
#define BOOL int;
声明布尔型变量时可以用BOOL代替int:
BOOL flag;
类型定义
上个标题中我们用#define指令创建了一个宏,可以用来定义布尔型数据:
#define BOOL int;
但是,一个更好的设置布尔型的方法是所谓的类型定义(type define)的特性:
typedef int Bool;
注意
- 定义的类型名放在后面
- 将首字母大写不是必须的,只是一些C程序员的习惯。
类型定义使得程序更易于理解,例如cash_in和cash_out都用来存储美元数量,我们可以将Dollars声明成
typedef float Dollars;
Dollars cash_in,cash_out;
问题:用typedef和用作类型的宏定义#define Dollars float
有什么区别?
- 作用域不同,#define在预处理时进行,作用于全局,typedef可作用于局部
- 实现效果不一定相同
#include <stdio.h>
#include <typeinfo>
#define POINTER int*
typedef int* Pointer2;
int main(){
int* a1,a2,a3,a4;
POINTER p1,p2,p3,p4;
Pointer2 p5,p6,p7,p8;
printf("%s %s %s %s\n",typeid(a1).name(),typeid(a2).name(),typeid(a3).name(),typeid(a4).name());
printf("%s %s %s %s\n",typeid(p1).name(),typeid(p2).name(),typeid(p3).name(),typeid(p4).name());
printf("%s %s %s %s\n",typeid(p5).name(),typeid(p6).name(),typeid(p7).name(),typeid(p8).name());
return 0;
}
运行上面的测试程序
输出结果为:
可见宏定义是简单的字符替换,当声明指针变量int*时,由于C语言的规范,一次只能声明一个,后续声明的变量将为int型,宏定义后效果也是如此。但typedef
更彻底地将int*
视为一个类型。
承接上述的
typedef float Dollars;
Dollars cash_in,cash_out;
这样的写法比下面的写法更有意义:
float cash_in, cash_out;
优点:
-
类型定义还可以使程序更容易修改。如果之后决定Dollars的实际应用类型修改为double,则只需要修改类型定义就足够了:
typedef double Dollars
如果不使用类型定义,则需要找出表示美元的变量并把声明中的float修改成double。
(这个有点宏定义也是可以实现的,不过类型定义不是全局的,修改起来更灵活)
类型定义是编写可移植程序的一种重要工具。程序从一台计算机移动到另一台计算机可能引发的问题之一就是不同计算机相同类型的取值范围(机器码位数)可能不同。如果i是int型变量,那么赋值语句i = 100000;
在一台使用32位整数的计算机上是没问题的,但是在一台使用16位整数的计算机上就会出错。简单口算一下32*1024(-215~215)<40000 无法表示100000。 -
可移植性技巧
为了更大的可移植性,可以考虑用typedef定义新的整数名。
假设编写的程序需要用变量来存储产品数量,取值在0~50000.为此可以使用long int型变量,但是用户更愿意使用int型变量,因为算数运算int型比long int型运算速度更快;同时,int型变量可以占用较少的空间。
我们可以定义自己的数量类型 ,而避免使用int类型声明数量变量;typedef int Quantity;
并且使用这种类型来声明变量:Quantity q;
打把程序转到小值整数的机器上时,需要改变Quantity的定义:
typedef long int Quantity;
可惜的是,这种变化无法解决所有问题,因为Quantity声明的变化可能会导致改变Quantity类型变量的使用方式。至少使用了Quantity类型的变量在scanf和printf函数的使用上需要改变,用转换说明%ld替换%d。
C语言库自身使用typedef为那些可能依据C语言实现的不同的类型创建类型名;这些类型名的名字经常以_t
结尾,比如ptrdiff_t
、size_t
、wchar_t
。