1、问题引入:
接触了typedef多时,对它的了解是:用来声明一个别名,typedef后面的语法,是一个声明。
其实,他同define的差别是比较大的,不仅仅是替换问题。
如下
typedef int a[10]; typedef void(*p)(void)
typedef int Fun() ;
用上面的概念能解释了吗?是用a[10]来代替Int吗?答案是NO!
2、别人的解释:
typedef int Fun() ;
定义了一个函数类型Fun,所有这个类型的函数都返回一个int类型的值。
举个例子,假定有两个分别计算加和减的函数
int sum(int a, int b)
{
return (a + b);
}
int sub(int a, int b)
{
return (a - b);
}
typedef int CalcType(int a, int b); //这样CalcType就成了返回值为int型,接受参数为两个整
//数的函数。
int main()
{
int select = -1;
int result;
int a;
int b;
CalcType calculate[] = {sum, sub}; //留意。
printf("Please selectcalculation type\n");
scanf("%d\n", select);
printf("Input two value\n");
scanf("%d %d\n", &a,&b);
if (select == 0 || select == 1)
result = calculate[select](a, b);
return (0);
}
3、我的理解
1)举个例子吧
int a[20]<=>int[] a=new int[20]//意思是开辟int型的20个地址空间给a,a的类型是a[]。
typedef charsstring[MAX]<=>typedef char[MAX] sstring //这样,sstring就可以定义一唯字符型数组了。
如:sstring s1<=>char s1[MAX]。
这样,我们再理解刚才上面提到的问题:
typedef int a[10]<=>typedefint[10] a //也就是说a可以去定义一唯整形数组了。
typedef void (*p)(void)<=>typedef void(void) *p //可以用p去定义指向返回值为空值,参数也为空值的函数了。
typedef int Fun() <=> typedefint() Fun //意思是Fun可以去定义返回值为int型的函数了。
下面对typedef作较为详细准备的解释:
2)使用 typedef为现有类型创建同义字。 定义易于记忆的类型名
typedef原类型名替换类型名;
如typedef int me;
me a;
typedef 还可以掩饰符合类型,如指针和数组。
char line[81];
定义一个 typedef,如下示:
typedef char Line[81];
Line text, secondline;
getline(text);
typedef struct tagNode
{
char *pItem;
pNode pNext;
} *pNode; //这样,pNode就相当于struct tagNode *;
pNode p;
同样,可以象下面这样隐藏指针语法:
typedef char * pstr;
int mystrcmp(pstr, pstr);
注意:标准函数 strcmp()有两个‘const char *'类型的参数。 ‘constpstr'被解释为‘char* const'(一个指向char 的常量指针),而不是‘constchar *'(指向常量char 的指针)。
typedef const char * cpstr;
int mystrcmp(cpstr, cpstr); // 现在是正确的
记住:不管什么时候,只要为指针声明 typedef,那么都要在最终的 typedef 名称中加一个 const,以使得该指针本身是常量,而不是对象。
3)代码简化
上面讨论的 typedef 行为有点像 #define 宏,用其实际类型替代同义字。不同点是 typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。例如:
typedef int (*PF) (const char *, constchar *);
这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。
再如一下面的三个例子(将复杂的式子用typedef简化):
对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
(1)int *(*a[5])(int, char*); 如下转化表达:
typedef int *(*pFun)(int, char*);//pFun是我们建的一个类型别名
pFun a[5]; //使用定义的新类型来声明对象,等价于int*(*a[5])(int, char*);
(2)void (*b[10]) (void (*)());
typedef void (*pFunParam)(); //首先为上面表达式斜体加粗部分声明一个新类型
typedef void (*pFun)(pFunParam); //整体声明一个新类型
pFun b[10]; //使用定义的新类型来声明对象,等价于void(*b[10]) (void (*)());
(3)doube(*)() (*pa)[9]; //首先为上面表达式斜体加粗部分声明一个新类型
typedef double(*pFun)(); //整体声明一个新类型
typedef pFun (*pFunParam)[9]; //使用定义的新类型来声明对象,等价于doube(*)()(*pa)[9];
pFunParam pa;
4)促进跨平台开发
typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以自动获得最高的精度:
typedef long double REAL;
在不支持 long double 的机器上,该 typedef 看起来会是下面这样:
typedef double REAL;
并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:
typedef float REAL;
在大多数情况下,甚至这个微小的变动完全都可以通过奇妙的条件编译来自动实现。标准库广泛地使用typedef 来创建这样的平台无关类型:
size_t,ptrdiff 和 fpos_t 就是其中的例子。此外,象 std::string 和 std::ofstream 这样的 typedef 还隐藏了长长的,难以理解的模板特化语法,例如:basic_string,allocator> 和 basic_ofstream>。
5)typedef 与#define的比较
(A)他们的不同:
我们以例子进行。
例一:
typedef char *pStr;
#define pStr char *;
通常讲,typedef要比#define要好,特别是在有指针的场合:
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;
在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。
#define用法的一个例子:
#define f(x) x*x
main( )
{
int a=6,b=2,c;
c=f(a) / f(b);
printf("%d \\n",c);
}
以下程序的输出结果是: 36,出错。
在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号:#define f(x) (x*x) ,这样才有正确结果。当然,使用typedef就没有这样的问题。
例二:
下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
是p2++出错了。上述代码中const pStr p2并不等于const char * p2,不是简单的替换。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。
(B)#define与typedef引申谈
1) #define宏定义的特别长处:可使用 #ifdef,#ifndef等来进行逻辑判断,使用#undef来取消定义。
2) typedef的特别长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。
6)typedef与存储关键字
typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并不是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef声明看起来象static,extern等类型的变量声明。第二个陷阱:
typedef register int FAST_COUNTER; // 错误
编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号typedef 已经占据了存储类关键字的位置,在typedef 声明中不能用 register(或任何其它存储类关键字)。
4、static
static 修饰变量和修饰函数的意义是不同的。
修饰变量是把该变量的作用与限制在某一范围内,这个范围可以是模块范围、函数范围、类范围、复合语句范围,但其生存期从进入其有效范围开始到程序运行结束。
static修饰函数时,是把这个函数的有效范围限制在定义他的模块内。
typedef 声明有助于创建平台无关类型,甚至能隐藏复杂和难以理解的语法。
typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。