typedef常见用法:
注:本文可能多次提得同一内容,这是我从别的地方整理的,希望能够谅解,不想看的直接跳过就行
1.常规变量类型定义例如:typedef unsigned char uchar描述:uchar等价于unsigned
char类型定义 uchar c声明等于unsignedchar c声明
2.数组类型定义例如:typedef int array[2];(注:可理解为typedef
int[] array)描述:array等价于 int[2]定义;
array a声明等价于inta[2]声明
扩展:typedefint array[M][N];描述:array等价于 int[M][N]定义;
array a声明等价于inta[M][N]声明
3.指针类型定义例如: typedef int *pointer;描述:pointer等价于
int*定义; pointer p声明等价于int*a声明
例如:typedef int *pointer[M];描述:pointer等价于 int*[M]定义;
pointer p声明等价于int*a[M]声明明
4.函数地址说明描述:C把函数名字当做函数的首地址来对待,我们可以使用最简单的方法得到函数地址例如:函数:int
func(void); unsigned long funcAddr=(unsigned long)func; funcAddr的值是func函数的首地址
5.函数声明例如:typedef int func(void); (注:可理解为typedefint
(void ) func) func等价于 int(void)类型函数描述1:
func f声明等价于 int f(void)声明,用于文件的函数声明描述2:
func *pf声明等价于 int (*pf)(void)声明,用于函数指针的生命,见下一条6.函数指针例如:typedef
int (*func)(void) (注:可理解为typedef int (void ) * func)描述:func等价于int
(*)(void)类型 func pf等价于int(*pf)(void)声明,pf是一个函数指针变量
7.识别typedef的方法:a).第一步。使用已知的类型定义替代typdef后面的名称,直到只剩下一个名字不识别为正确如typedefu32(*func)(u8);从上面的定义中找到
typedef__u32u32;typedef __u8 u8继续找到 typedef unsigned int__u32;typedef unsigned char __u8;替代位置名称 typedef
unsignedint(*func)(void);现在只有func属于未知b).第二步.未知名字为定义类型,类型为取出名称和typedef的所有部分,如上为func等价于unsignedunsignedint(*)(unsignedchar);c).第三部.定义一个变量时,变量类型等价于把变量替代未知名字的位置所得到的类型func
f等价于unsigned unsignedint(*f)(unsigned char);
下面我们利用上面的方法分析一个稍微复杂点的函数声明:
int (*Instance (int (*pf)(const char *,const char *)))(const char *, const char *);
咋一看还真有点蒙,但是我们试着使用上面的方法整理一下这个声明:
typedef int(*Parameter)(constchar *, const char *);
Parameter等价于int(*)(const char *, const char *);
所以上面的声明等价于Parameter Instance(Parameter pf);
这样一抽象,我们理解起来就相对容易多了.
Typedef和define的区别
1.首先,二者执行时间不同
关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。
Define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。
#define用法例子:
#define f(x) x*xmain( ){ int a=6,b=2,c; c=f(a) / f(b); printf("%d\\n",c);}
程序的输出结果是: 36,根本原因就在于#define只是简单的字符串替换。
2.功能不同
Typedef用来定义类型的别名,这些类型不只包含内部类型(int,char等),还包括自定义类型(如struct),可以起到使类型易于记忆的功能。
如: typedef int (*PF) (const char *, const char *);
定义一个指向函数的指针的数据类型PF,其中函数返回值为int,参数为const char *。
typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫REAL 的浮点类型,在目标机器上它可以i获得最高的精度:typedef long double REAL;在不支持 long double 的机器上,该 typedef 看起来会是下面这样:typedef double REAL;并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:typedef
float REAL;
#include<stdio.h>
typedef int arr[10];
void main()
{
arr a;
int i;
for(i=0;i<10;i++)
{
a=i*i;
printf("%d\n",a);
}
}
#define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。
3.作用域不同
#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。
而typedef有自己的作用域。
void fun()
{
#define A int
}
void gun()
{
//在这里也可以使用A,因为宏替换没有作用域,
//但如果上面用的是typedef,那这里就不能用A ,不过一般不在函数内使用typedef
}
4.对指针的操作
二者修饰指针类型时,作用不同。
Typedef int * pint;
#define PINT int *
Const pint p;//p不可更改,p指向的内容可以更改,相当于 int
* const p;
Const PINT p;//p可以更改,p指向的内容不能更改,相当于 const
int *p;或 int const *p;
pint s1, s2; //s1和s2都是int型指针
PINT s3, s4; //相当于int * s3,s4;只有一个是指针。
typedef的四个用途和两个陷阱
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa,pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
// 和一个字符变量;
以下则可行:
typedef char*PCHAR; // 一般用大写
PCHAR pa,pb;// 可行,同时声明了两个指向字符变量的指针
虽然:
char *pa, *pb;
也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。
用途二:
用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名对象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1p1;
而在C++中,则可以直接写:结构名 对象名,即:
tagPOINT1 p1;
估计某人觉得经常多写一个struct太麻烦了,于是就发明了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1;// 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
用途三:
用typedef来定义与平台无关的类型。
比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef longdouble REAL;
在不支持 longdouble 的平台二上,改为:
typedef doubleREAL;
在连 double 都不支持的平台三上,改为:
typedef floatREAL;
也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:
1. 原声明:int *(*a[5])(int,char*);可以写成int * (int,char *) * [] a;
变量名为a,直接用一个新别名pFun替换a就可以了:
typedef int*(*pFun)(int, char*);
原声明的最简化版:
pFun a[5];
2. 原声明:void (*b[10])(void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void(*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void(*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];
3. 原声明:doube(*)() (*e)[9];
变量名为e,先替换左边部分,pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny(*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;
理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
int (*func)(int *p);
首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明 (*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func[5])(int *);
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。
也可以记住2个模式:
type (*)(....)函数指针
type (*)[]数组指针
---------------------------------
陷阱一:
记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:
先定义:
typedef char* PSTR;
然后:
int mystrcmp(constPSTR, const PSTR);
const PSTR实际上相当于constchar*吗?不是的,它实际上相当于char* const。
原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。
简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。
陷阱二:
typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedefstatic intINT2; //不可行
编译将失败,会提示“指定了一个以上的存储类”。
#define,const,typedef三者联系与区别
一. #define与const
联系:都可以用来定义常量
区别:
1. const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。
2. 前者在堆栈分配了空间,而后者只是把具体数值直接传递到目标变量罢了。或者说,const的常量是一个Run-Time的概念,他在程序中确确实实的存在并可以被调用、传递。而#define常量则是一个Compile-Time概念,它的生命周期止于编译期:在实际程序中他只是一个常数、一个命令中的参数,没有实际的存在。
3.const常量存在于程序的数据段,#define常量存在于程序的代码段。
4. 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试
看如下例子:
E), #define INT32 int
unsigned INT32 i =10;
F),typedef int int32;
unsigned int32 j =10;
其中F)编译出错,为什么呢?E)不会出错,这很好理解,因为在预编译的时候INT32
被替换为int,而unsigned int i = 10;语句是正确的。但是,很可惜,用typedef取的别
名不支持这种类型扩展。另外,想想typedefstatic int int32 行不行?为什么?
答:估计编译器将这句话理解为:unsigned ( int) int j =10; 即INT32代表的 int 和unsigned ( int ) 是两次声明,所以出错。
typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性。
typedef小结
typedef关键字
typedef的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别
名,而非定义一个新的数据类型。
比如:华美绝伦的芍药,就有个别名---“将离”。中国古代男女交往,往往以芍药相赠,表达惜别之情,送芍药就意味着即将分离。这样新的名字与原来的名字相比,就更能表达出想要表达的意思。
typedef struct student
{
//code
}Stu_st,*Stu_pst;//命名规则请参考本章前面部分
A),structstudent stu1;和Stu_st stu1;没有区别。
B),structstudent *stu2;和Stu_pst stu2;和Stu_st*stu2;没有区别。
typedef作用范围
typedef的最大作用范围只能是其所在的编译单元,不同C文件里面的typedef相互独立,完全没有任何限制。不同函数体也相互独立
#include <stdio.h>
typedef double INT32;
INT32 gb ='a';//sizeof gb =8double
int main()
{
typedef intINT32;
INT32b = 'a'; //sizeof b=4 int
return 0;
}
typedef的四个用途和三个陷阱
用途一:定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:char*pa,pb;尤其在需要大量指针的地方,typedef的方式更省事。
用途二:定义struct详细分析见另一篇文章..
用途三:用typedef来定义与平台无关的类型。
比如定义一个叫REAL的浮点类型,
在目标平台一上,让它表示最高精度的类型为:typedeflongdoubleREAL;
在不支持longdouble的平台二上,改为:typedefdoubleREAL;
在连double都不支持的平台三上,改为:typedeffloatREAL;
也就是说,当跨平台时,只要改下typedef本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。
用途四:为复杂的声明定义一个新的简单的别名。
方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。
理解复杂声明可用的“右左法则”:
从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;
括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。
举例:int(*func)(int *p);
首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int(*func[5])(int *);
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。
也可以记住2个模式:
type(*)(....)函数指针
type(*)[]数组指针
陷阱一:不能组合使用
typedef double INT32;
unsigned INT32 ga;//错误的写法
陷阱二:(与const连用)
记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如:
先定义:typedefchar*PSTR;
然后:
intmystrcmp(constPSTR,constPSTR);
constPSTR相当于constchar*吗?不是的,它实际上相当于char*const。
原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char*const。
指针本身是const的指针指向的变量是可以变的。
简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换。
陷阱三:
typedef在语法上是个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedefstaticintINT2;//不可行编译将失败,会提示“指定了一个以上的存储类”。
分享到:
相关推荐
详解typedef四用途与两陷阱 typedef语法 声明一个别名 区别于#define思维与用法 详细解析了typedef的四个重要用途与两个误区
1.4 使用#define和#include 1.5 使用printf()和scanf() 1.6 控制流 1.7 函数 1.8 数组、字符串和指针 1.8.1 数组 1.8.2 字符串 1.8.3 指针 1.9 文件 1.10 与操作系统有关的内容 1.10.1 编写和运行c程序 1.10.2 ...
希望大家下载后好好的阅读代码,难的地方还有解析,应该会帮到你的 1 葱花炒鸡蛋 4.000000 2 红烧鲤鱼 66.000000 3 麻辣豆腐 4.000000 4 东坡肘子 33.000000 5 北京烤鸭 108.000000 6 鲤鱼跃龙门 666.000000 7 南京...
在学习C语言和C++过程中,我们接触了许多的关键字,下边我们再来回顾一下使用频率比较高的几个关键字:#define(宏定义)、static(静态变量)、const(只读变量)volatile(直接从内存读数据)、typedef
cgi.h 代码如下:#ifndef CGI_H#define CGI_H #include <stdio>#include <string>#include typedef struct Node{ char *name; char *value; struct Node *next;}Node; typedef struct Index{ Node *head; char ...
汗啊,因为验证例子是从某个程序中抽取出来,里面包含一个很简单的http的解析。我本来想update资源,没有找到 update的方法。需要说明的是这部分和真正的算法没有直接关系。放在这里,太长了,如果需要的网友,请到...
与strlen、sizeof、const、volatile、void、void*、#define、typedef、realloc、malloc、calloc等相关的一些陷阱知识点的解析; 时间复杂度、冒泡排序法、选择排序法、快速排序法、归并排序法、顺序排序法、二...
与strlen、sizeof、const、volatile、void、void*、#define、typedef、realloc、malloc、calloc等相关的一些陷阱知识点的解析; 时间复杂度、冒泡排序法、选择排序法、快速排序法、归并排序法、顺序排序法、...
面试题6:#define CHAR char*和typedef char* CHAR各有什么优劣 面试题7:谈谈你对typedef的认识 4.2 const(常量) 面试题8:关键字const是什么 面试题9:说明以下a声明的含义 面试题10:const、define定义常量的...
实验内容: 建立无向图的邻接矩阵 图的深度优先搜索 图的广度优先搜索 三、实验步骤及结果: 建立无向图的邻接矩阵: 源代码: #include "stdio.h" #include "stdlib.h" #define MAXSIZE 30 typedef struct 数据...
Red Panda Dev C ++(小熊猫Dev-C ++,旧名称Dev-C ++ 2000)是Orwell Dev-C ++的改进版。 自2015年以来,Orwell Dev-C ++已停止更新,因此我对此进行了分叉。... 正确显示#define / typedef / enum /
1.13 对于用户定义类型,typedef 和#define有什么区别? 1.14 我似乎不能成功定义一个链表。我试过typedef struct{char *item; NODEPTR next;}* NODEPTR; 但是编译器报了错误信息。难道在C语言中结构不能包含指向...
1.17.3,typedef与#define的区别.........................45 1.17.4,#define a int[10]与 typedef int a[10];.... 46 第二章 符号................. 49 2.1,注释符号......50 2.1.1,几个似非而是的注释问题.......
然后根据解析命令行,调用相应的函数来完成我们所需要的操作。 顺便联想一下。int main(int argc,char * argv[])参数的使用。 比如命令行输入: cfile computer C_Langle .此时argc=3. argv[]指向3个字符串,这些...
/* Mark:mp4封装解析接口 /* author: machh /* date:2012.5.12. /******************************************/ #ifndef _MP4_INTERFACE_ #define _MP4_INTERFACE_ #include "MP4Writer.h" #include "MP4Reader.h" ...
1.13 对于用户定义类型,typedef 和#define有什么区别? 7 1.14 我似乎不能成功定义一个链表。我试过typedef struct{char *item; NODEPTR next;}* NODEPTR; 但是编译器报了错误信息。难道在C语言中结构不能包含...
ARP (Address Resolution Protocol)(地址解析協議) 18.IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。 2.用户输入M,N...
1.13 对于用户定义类型,typedef和#define有什么区别? 1.14 我似乎不能成功定义一个链表。我试过typedefstruct{char*item;NODEPTRnext;}*NODEPTR;但是编译器报了错误信息。难道在C语言中结构不能包含指向自己的...