伟大的缝纫师—typedef
- 一.历史的误会—也许应该是typerename
- 二.typedef和#define的区别
一.历史的误会—也许应该是typerename
为什么这样说呢?因为typedf其实就是一个重命名关键字,看示例
这里我觉得unsigned int太长了,我将它改名为u_int,这样在书写过程中更方便
下面来看一些奇怪的例子
这里看起来有些奇怪,但抓住本质。int*是原本的类型,而int_p是我对它的重命名
看一看对结构体的重命名
这是我们原本的结构体使用,stu_t是该结构体的一个全局变量,struct stu x是该结构体的临时变量(如果不怎么了解结构体的可以看看这篇博客 什么是结构体)
如果我们对其重命名后,stu_t就不再是全局变量了,而是struct stu重命名后的名字,这样写更加方便
对数组的重命名
这是我们平常定义一个叫a的数组
可以看到,一旦我们加上typedef,那么a就不再代表数组名了,更应该称为一种类型,就相当于用现在的a代替(当然并非简单的替换,这里只是方便理解)原来的int [10],从监视中也可以看到,用a定以b,b就变成了一个大小为10的整形数组
总结一下:typedef就是对类型进行重命名的解决方案。它存在的意义就是帮助我们从冗长的类型命名里解放出来。一般使用它对我们一些不太好理解的类型进行简化
ps:typedef虽然好用但别过的使用,因为这毫无疑问会给我们带来阅读成本,例如一个数组用a来代替,那么a b,阅读者根本不知道它数组的具体类型和元素个数。建议一般在使用结构体时使用
二.typedef和#define的区别
可以看到a是int*类型而b是int类型,这是因为a离得更近。具体为什么就是系统的规定
那其实我们也可以这样写,但不推荐,可读性太差。接下来回归正题
从上可以看到a,b两个都是指针类型了。所以可以看出使用typedef并不是简单的替换,更应该理解成一种全新的类型,像是int_p因为它没有*号,所以不存在跟谁结合的问题。它对其后的所有变量都赋予该类型
接下来看看#define的区别
区别一
看以上的代码,能否通过呢?a,b,c的类型又是什么呢?
可以看到这样写和我们直接int*a,b,c的结果是一样的,为什么呢?
这里需要和typedef区分开来,tydefy本质上是重命名而不是文本替换,它相当于形成了一个新的类型,即使它有时使用起来和直接写没区别。而宏定义进行的是文本替换,换句话说编译器第一步进行预处理时,会直接将我们的int*替换至ptr_t处,于是可以回答上面的问题,既然是等价替换,那么结果当然相同啦
区别二
这样写是可以编过的,那下面呢?
这里很明显的看到65报错而64行却没报错。这里也很好理解,前文说到宏是进行文本替换,所以这里INT32就直接被替换为了int,前面再加个unsigned当然没问题。而前文也说到typedef所修饰类型是一个独立的类型,编译器就会认为这是int32类型而不是int类型,即使它们的作用相同,因此你当然不能加一个unsiged,编译器会感到疑惑,unsiged int32是什么类型。
结论:1.宏在类型处理时秉承着类型替换的原则而typedef秉承着文本重命名的原则。并且typedef所修饰的类型后不能加其他关键字组成新的类型(即使它们原本可以)