用了C和C++这么久,今天才仔细研究了下typedef的用法,真的是惭愧啊,不过基础都是不断巩固的啊。

typedef

在计算机编程语言中用来为复杂的声明定义简单的别名,与宏定义有些差异。它本身是一种存储类的关键字,与auto、extern、mutable、static、register等关键字不能出现在同一个表达式中。

1. typedef和结构体问题

当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?莫非C语言不允许在结构中包含指向它自己的指针吗?请你先猜想一下,然后看下文说明:

 typedef struct tagNode
{ char* pItem; pNode pNext; }*pNode;

举个例子:

 typedef struct tagMyStruct
{ int iNum; long lLength; }MyStruct;
这语句实际上完成两个操作:
1) 定义一个新的结构类型
 struct tagMyStruct
{ int iNum; long lLength; };
分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。
我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。
2) typedef为这个新的结构起了一个名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;
因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。
答案与分析
C语言当然允许在结构中包含指向它自己的指针,我们可以在建立链表等数据结构的实现上看到无数这样的例子,上述代码的根本问题在于typedef的应用。
根据我们上面的阐述可以知道:新结构建立的过程中遇到了pNext域的声明,类型是pNode,要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode。

2. typedef和define的区别

有下面两种定义pStr数据类型的方法,两者有什么不同?哪一种更好一点?

 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语句必须写成 pStr2 s3, *s4; 这样才能正常执行。

3.  const问题

下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?

 typedef char *pStr;
char string[]="abc";
const char *p1=string;
const pStr p2=string;
p1++;
p2++;
答案与分析:
是p2++出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和pStr const p2本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。
#define与typedef引申谈
1) #define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。
2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。

4. tyepdef和复杂的变量声明

理解复杂声明可用的“右左法则”:
  从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
  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作简化自有其价值,比如:
下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?
 int *(*a[])(int, char*);
void (*b[]) (void (*)());
doube(* (*pa)[])();
答案与分析:
对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
 int *(*a[])(int, char*);
//pFun是我们建的一个类型别名
typedef int *(*pFun)(int, char*);
//使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);
pFun a[5];
 
 void (*b[]) (void (*)());
//首先为上面表达式蓝色部分声明一个新类型
typedef void (*pFunParam)();
//整体声明一个新类型
typedef void (*pFun)(pFunParam);
//使用定义的新类型来声明对象,等价于void (*b[10]) (void (*)());
pFun b[10];
 
 double(*[]  (*pa)[])()[]  ;
//首先为上面表达式蓝色部分声明一个新类型
typedef double(*pFun)();
//整体声明一个新类型
typedef pFun (*pFunParam)[9];
//使用定义的新类型来声明对象,等价于double(*(*pa)[9])();
pFunParam pa;
pa是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是“doube(*)()”--也即一个指针,指向一个函数,函数参数为空,返回值是“double”。

typedef的用法和相关问题的更多相关文章

  1. struct和typedef struct用法和区别

    1 首先://注意在C和C++里不同 1.1 在C中定义一个结构体类型要用typedef: typedef struct Student { int a; }Stu; 于是在声明变量的时候就可:Stu ...

  2. C++/C中的struct和typedef struct用法和区别

    struct和typedef struct 分三块来讲述: 1 首先://注意在C和C++里不同 在C中定义一个结构体类型要用typedef: typedef struct Student { int ...

  3. 李洪强iOS开发之 - enum与typedef enum的用法

    李洪强iOS开发之 - enum与typedef enum的用法 01 - 定义枚举类型 上面我们就在ViewController.h定义了一个枚举类型,枚举类型的值默认是连续的自然数,例如例子中的T ...

  4. runtime记录

    前言: 最初对于runtime的了解其实只停留在,知道这是一组C的方法,知道消息机制中会把方法调用转成objc_msgSend(theObject,@selector(objectMethod)).随 ...

  5. iOS是怎么"绘画"的?

    什么是绘图引擎 如果您以前从事其它平台的图形/界面开发或者游戏开发,一定知道, 不管上层UI怎么呈现和响应, 底层必须有一个绘图引擎. iOS也不例外. 本文详细介绍了iOS Graphics的用法和 ...

  6. React Native 组件之TextInput

    React Native 组件之TextInput类似于iOS中的UITextView或者UITextField,是作为一个文字输入的组件,下面的TextInput的用法和相关属性. /** * Sa ...

  7. SIP 状态码

    SIP应答消息状态码 与功能 类型 状态码 状态说明临时应答(1XX) 100 Trying 正在处理中180 Ringing 振铃181 call being forwarder 呼叫正在前向182 ...

  8. http status 400,http 400,400 错误

    转载:http://blog.csdn.net/xu_zh_h/article/details/2294233 4 请求失败4xx 4xx应答定义了特定服务器响应的请求失败的情况.客户端不应当在不更改 ...

  9. 第二章排错的工具:调试器Windbg(上)

    感谢博主 http://book.51cto.com/art/200711/59731.htm <Windows用户态程序高效排错>第二章主要介绍用户态调试相关的知识和工具.本文主要讲了排 ...

随机推荐

  1. 基于 Laravel 开发博客应用系列 —— 项目必备软件安装

    1.概述 通过本项目我们将会构建一个简单.清爽.优雅的博客系统,以及维护管理该博客的后台. 本项目源码公开在GitHub上:https://github.com/ChuckHeintzelman/l5 ...

  2. 《Android源码设计模式》--单例模式

    No1: 懒汉单例模式优缺点分析 public class Singleton{ private static Singleton instance; private Singleton(){} pu ...

  3. 同步 Visual Studio Code 的设置与插件

    工具推荐:Settings Sync. 小心有坑! VS Code 没有账号系统,所以设置不能同步,在多终端使用时不是很方便. 有一款插件能做这个事情:Settings Sync - Visual S ...

  4. mysql正则表达式,实现多个字段匹配多个like模糊查询

    现在有这么一个需求 一个questions表,字段有题目(TestSubject),选项(AnswerA,AnswerB,AnswerC,AnswerD,AnswerE) 要求字段不包含png,jpg ...

  5. NOIP2018游记(更新完毕)

    10.13 初赛 Day -1 考前 这一次的考场从暗♂德华兴改到了长沙市一中,一进去:我一看,考场在哪???这一中比长郡大了好多,而且连指示牌都没有,这时碰见了谢总,谢总告诉我们在第二教学楼.路上还 ...

  6. TPS和QPS是什么,他们的区别是什么

    一.TPS:Transactions Per Second(每秒传输的事物处理个数),即服务器每秒处理的事务数.TPS包括一条消息入和一条消息出,加上一次用户数据库访问.(业务TPS = CAPS × ...

  7. HTTP请求的GET与POST方式的区别

    Form中的get和post方法,在数据传输过程中分别对应了HTTP协议中的GET和POST方法.二者主要区别如下: 1)Get是用来从服务器上获得数据,而Post是用来向服务器上传递数据: 2)Ge ...

  8. 【SQL】177. Nth Highest Salary

    Write a SQL query to get the nth highest salary from the Employee table. +----+--------+ | Id | Sala ...

  9. Python 面向对象编程——继承和多态

    <基本定义>     在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超 ...

  10. c++ 时间相关的类型

    关于时间转换可以参考以下博客: https://www.jianshu.com/p/80de04b41c31 https://www.cnblogs.com/qicosmos/p/3642712.ht ...