深入理解typedef
首先请看看下面这两句:
typedef int a[10]; typedef void (*p)(void);
如果你能一眼就看出它们的意思,那请不要再往下看了。如果你不太理解,或概念还有些模糊,请继续往下看吧。
typedef用来声明一个别名,typedef后面的语法,是一个声明。本来这里不会产生什么误解的,但结果却出乎意料,产生误解的人不在少数。罪魁祸首又是那些害人的教材。在这些教材中介绍typedef的时候通常会写出如下形式:
typedef int PARA;
这种形式跟#define int PARA几乎一样!这些教材的宗旨是由浅入深,但实际做出来的行为却是以偏盖全!
的确,这种形式在所有形式中是最简单的,但却没有对 typedef进一步解释,使得不少人用#define的思维来看待typedef,把int与PARA分开来看,int是一部分,PARA是另一部分,但实际上根本就不是这么一回事。int与PARA是一个整体!就象int i:声明一样是一个整体声明,只不过int i定义了一个变量,而typedef定义了一个别名。
由于持有这种错误的观念,就会无法理解如下一些声明:
typedef int a[10]; typedef void (*p)(void);
会以为a[10]是int的别名,(*p)(void)是void的别名,但这样的别名看起来又似乎不是合法的名字,于是陷入困惑之中。实际上,上面的语句把a声明为具有10个int元素的数组的类型别名,p是一种函数指针的类型别名。
虽然在功能上,typedef可以看作一个跟int PARA分离的动作,但语法上typedef属于存储类声明说明符,因此严格来说,typedef int PARA整个是一个完整的声明。
定义一个函数指针类型。比如原函数是:
void func(void);
那么定义的函数指针类型就是:
typedef void (*Fun)(void);
然后用此类型生成一个指向函数的指针:
Fun func1;
当func1获取函数地址之后,那么你就可以向调用原函数那样来使用这个函数指针:func1(void);
下面是理解typedef的正确方法,分为以下几步:
1. 确定被声明的类型:遇到typedef时,从左到右进行扫描,找到第一个“陌生”的标志符,这个标志符就应该是语句所声明的类型名称。例如: typedef int* (* pt)(int* (*pn)(int * p1,int *p2),int * p3); 如果pt是生词(既不是保留字,也不是生命过的类型),那么它就是要声明的类型。其它的名字都是为了阅读方便的占位符,可有可无。也就是说,上面的语句等价为: typedef int * (*pt)(int * (*)(int *, int *),int *);
2. 之后一旦遇到该类型声明的变量,则在该类型的typedef式中用变量代替类型,去掉typedef关键字,所得到的声明式等价与原来的声明。例如: pt p; 这个声明式,可以经过两步变化为等价的声明式。
首先,回到pt的typedef式: typedef int * (*pt)(int * (*)(int *, int *),int *); 用p代替pt: typedef int * (*p)(int * (*)(int *, int *),int *); 然后把typedef去掉,得到: int * (*p)(int * (*)(int *, int *),int *); 这个语句与 pt p;意义相同。
如果基础扎实,应该知道,这是个函数指针的声明,所指向的函数有两个int * 参数,返回一个int *值,第二个参数是int * ,整个函数返回一个int *。
typedef和define的区别
typedef和define都可以用来给对象取一个别名,但是两者却有着很大不同。
1. 首先,二者执行时间不同 关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。 Define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。
#define用法例子: #define f(x) x*x main( ) { 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;
#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的更多相关文章
- 理解typedef(转)
// 从别人那转的,调整下格式便于阅读. 首先请看看下面这两句: typedef ]; typedef void (*p)(void); 如果你能一眼就看出它们的意思,那请不要再往下看了.如果你不太理 ...
- 如何理解typedef void (*pfun)(void)
问题: 在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一"块"东西,而不是两"块"东西呢?那 ...
- 函数指针-如何理解typedef void (*pfun)(void)
问题: 在刚接触typedef void (*pfun)(void) 这个结构的时候,存在疑惑,为什么typedef后只有一"块"东西,而不是两"块"东西呢?那 ...
- 一步步理解typedef
1.如何用C语言实现一个函数,传递两个整形数,返回两个数的和? #include<stdio.h> int add(int a,int b) { return a+b; } void ma ...
- NRF51822+STM32bootload——typedef void (*Fun) (void) 理解
1.typdef 用法如下所示 typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned ...
- C语言语法 typedef小结
在总结typedef之前,先了解一个专业术语: 常量指针(const pointer):常量指针在定义的时候必须被初始化,而且一旦初始化完成,则它的值就不能再改变. int errNumb = 0; ...
- typedef 揭秘
typedef用来声明一个别名,typedef关键字后面是一个声明.语法上typedef属于存储类声明说明符 一.引言 如果你理解typedef的简单形式: typedef int PARA; 这种形 ...
- 操作系统开发系列—解释typedef void (*int_handler) ();
于是我换了一个思路来理解这个typedef 我们首先看常规的变量定义: int INT//定义了一个名为INT的int型变量. char *c//定义了一个名为c的char型指针变量 void(*Fu ...
- (转)深入理解PHP之数组(遍历顺序)
深入理解PHP之数组(遍历顺序)(转) http://www.laruence.com/2009/08/23/1065.html (鸟哥) 经常会有人问我, PHP的数组, 如果用foreach来访问 ...
随机推荐
- 简单的 jQuery 浮动层随窗口滚动滑动插件实例
写了一个非常简单的 jQuery 插件实例 浮动层随窗口滚动滑动 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional/ ...
- String类之indexOf--->查找某字对应的位置
以下方法都是java内置类String类的内置方法(不是构造方法哦,就是普通的方法),不需要我们写,直接拿过来用即可. indexOf方法对应Api介绍 lastIndexOf方法对应Api介绍 -- ...
- iOS开发自定义流水布局
//集成UICollectionViewFlowLayout 自己写的布局 // SJBFlowLayout.m // 自定义流水布局 // // Created by zyyt on 16/7 ...
- PAT 团体程序设计天梯赛-练习集 L1-019. 谁先倒
给出甲.乙两人的酒量(最多能喝多少杯不倒)和划拳记录,请你判断两个人谁先倒. 输入格式: 输入第一行先后给出甲.乙两人的酒量(不超过100的非负整数),以空格分隔.下一行给出一个正整数N(<=1 ...
- php基础(七)文件
PHP 文件处理 PHP 操作文件 当您操作文件时必须非常小心.如果您操作失误,可能会造成非常严重的破坏.常见的错误是: 编辑错误的文件 被垃圾数据填满硬盘 意外删除文件内容 PHP readfile ...
- js for...in 语句
原文链接:http://www.w3school.com.cn/js/js_loop_for_in.asp for...in 语句用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作). 实例 ...
- Java Object 对象拷贝答疑
Java Object 对象拷贝答疑 @author ixenos 摘要:在对象的clone过程需要注意的几点.关于关键字this.super 关于clone[对象拷贝] 在实际编程过程,有时候我们会 ...
- Lua高级教程Metatables
什么是Metatable metatable是Lua中的重要概念,每一个table都可以加上metatable,以改变相应的table的行为. Metatables举例 -- 声明一个正常的关系变量 ...
- solr定时增量索引
当数据库的数据发生改变的时候,我们不想手动的去重新添加数据库的数据导solr索引库中,所以用到定时添加索引.增删改的数据.现在写的这些都是基于我之前做的一步步到这来的. 将solr/dist下的sol ...
- 文字编码转换器 V1.0 免费绿色版
软件名称: 文字编码转换器 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win7 / Vista / WinXP 软件大小: 920KB 图片预览: 软件简介: 文字编码转换器,能把普通文 ...