1.typedef关键字
1.1简单介绍
C语言允许用户使用 typedef 关键字来定义自己习惯的数据类型名称,来替代系统默认的基本类型名称、数组类型名称、指针类型名称与用户自定义的结构型名称、共用型名称、枚举型名称等。一旦用户在程序中定义了自己的数据类型名称,就可以在该程序中用自己的数据类型名称来定义变量的类型、数组的类型、指针变量的类型与函数的类型等。
1.2简单用法
typedef的4种主要用法
1)为基本数据类型定义新的类型名。有利于增强程序的可拓展性。
示例:
typedef long double REAL;
typedef unsigned int COUNT;
当跨平台移植程序时,我们只需要修改一下 typedef 的定义即可,而不用对其他源代码做任何修改。其实,标准库中广泛地使用了这个技巧,比如 size_t 在 VC++2010 的 crtdefs.h 文件中的定义如下所示:
#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef _W64 unsigned int size_t;
#endif
#define _SIZE_T_DEFINED
#endif
2)为自定义数据类型(结构体、共用体和枚举类型)定义简洁的类型名称。
以结构体为例,下面我们定义一个名为 Game的结构体
struct Game
{
char * rule;
char * name;
int age;
};
在调用这个结构体时,我们必须像下面的代码这样来调用这个结构体:
strucy Game game1 = {"man","tom",20};
在这里,结构体 struct Game为新的数据类型,在定义变量的时候均要向上面的调用方法一样有保留字 struct,而不能像 int 和 double 那样直接使用 Game 来定义变量。现在,我们利用 typedef 定义这个结构体,如下面的代码所示:
typedef struct itGame
{
char * rule;
char * name;
int age;
}Game;
在上面的代码中,实际上完成了两个操作:
1)定义了一个新的结构体itGame
2)使用 typedef 为这个新的结构起了一个别名,叫 Point,即:
typedef struct itGame Game;
但是typedef还是有坑的,例子如下:
在写链表时经常有:
typedef struct tagNode
{
char *pItem;
pNode pNext;
} *pNode;
上面的示例代码与前面的定义方法相同,所以应该没有什么问题。但是编译器却报了一个错误,为什么呢?莫非 C 语言不允许在结构中包含指向它自己的指针?
其实是因为:新结构建立的过程中遇到了 pNext 声明,其类型是 pNode。这里要特别注意的是,pNode 表示的是该结构体的新别名。于是问题出现了,在结构体类型本身还没有建立完成的时候,编译器根本就不认识 pNode,因为这个结构体类型的新别名还不存在,所以自然就会报错。因此,我们要做一些适当的调整,比如将结构体中的 pNext 声明修改成如下方式:
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext;
} *pNode;
3)为数组定义简洁的类型名称
例如:
typedef int int_Array[10];
int_Array arr;
4)为指针定义简洁的名称
typedef char* PCHAR;
PCHAR arr;
适用于复杂类型的重命名
int *(*a[5])(int,char*);
除此之外还有一点需要特别注意:
typedef char* PCHAR;
int strcmp(const PCHAR,const PCHAR);
这里的“const PCHAR” 不是 “const char*”,而是char* const,因为typedef修饰的是一个指针所以const也是一样,此时const修饰的是一个指针并非所指的变量。
还需要特别注意的是,虽然 typedef 并不真正影响对象的存储特性,但在语法上它还是一个存储类的关键字,就像 auto、extern、static 和 register 等关键字一样。
2.define关键字
2.1简单介绍
C语言中,可以用 #define 定义一个标识符来表示一个常量。其特点是:定义的标识符不占内存,只是一个临时的符号,预处理后这个符号就不存在了。
用 #define 定义标识符的一般形式为:
#define 标识符 常量
凡是以“#”开头的均为预处理指令,#define也不例外。//在预处理时都会被替换。
还有变量名表示的是一个变量,但宏名表示的是一个常量。可以给变量赋值,但绝不能给常量赋值。
2.2解决的问题
宏定义最大的好处是“方便程序的修改”。使用宏定义可以用宏代替一个在程序中经常使用的常量。注意,是“经常”使用的。这样,当需要改变这个常量的值时,就不需要对整个程序一个一个进行修改,只需修改宏定义中的常量即可。且当常量比较长时,使用宏就可以用较短的有意义的标识符来代替它,这样编程的时候就会更方便,不容易出错。因此,宏定义的优点就是方便和易于维护。
2.3注意
宏定义 #define 一般都写在函数外面,与 #include 写在一起。当然,写在函数里面也没有语法错误,但通常不那么写。#define 的作用域为自 #define 那一行起到源程序结束。如果要终止其作用域可以使用 #undef 命令,格式为:
#undef
标识符undef 后面的标识符表示你所要终止的宏。比如前面在程序开头用 define 定义了一个宏 M,它原本的作用范围是一直到程序结束,但如果现在在程序中某个位置加了一句:
#undef 宏名
那么这个宏的作用范围到此就结束了。#undef 用得不多,但大家要了解。
2.3简单实例
#define MAX 100
2.4特别注意的与typedef的不同
看以下代码:
#include<iostream>
#include<typeinfo>
using namespace std;
#define PIN1 int *
typedef int * PIN2;
int main()
{
PIN1 a,b;
cout<<"用define类型为 "<<typeid(a).name()<<" "<<typeid(b).name()<<endl;
PIN2 c,d;
cout<<"用typedef类型为 "<<typeid(c).name()<<" "<<typeid(d).name()<<endl;
return 0;
}
DEVC++输出如下:
这里先提一下怎么查看变量类型
使用typeinfo库里的typeid(变量).name()
如果想再了解可以查看以下文章
c++查看变量类型
在DECC++里Pi我指针,i为int类型
由上图可知define与typedef的不同。