typedef 深入剖析
typedef是一个我们常常会用到的关键字,而这个关键字有许多陷阱或者说许多不为我们深入理解的地方。很多书上都是很简单地一笔代过,并没有真正地让我们理解这个关键字。本文对其进行详细地说明。
综合网络上找到的资料对其进行分析,这其中会涉及到一些其他c方面的内容(比如指针,指向函数的指针,编译时候数据类型未定义与完全定义知识等等),看到这些内容的时候大家可以忽略,这个重点是在typedef。
好了,不说那么多开始吧。
<h4>typedef的定义</h4>
typedef 是一个关键字,后面是数据类型和标识符。标识符或类型名并没有引入新的类型,而只是现有数据类型的同义词。
它用来对一个类型起一个新名字,也用来声明自定义数据类型,其实给一个类型起新名字的作用也包含在声明自定义数据类型这个功能中。
1.给一个类型起一个新名字
给一个类型其新名字,有时候可以帮助我们更好地记忆。
例子:
<pre lang="c" escaped="true">typedef int inter;</pre>
此声明定义了一个 int 的同义字,名字为 inter。注意 在这里typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 inter,即可以用inter来代替int进行整数变量的定义。
这个功能是最常用的,而且相对来说是比较简单的。
2.定义新的类型
定义新的类型有多种形式,下面简单的列一些。
<pre lang="c" escaped="true">typedef BaseType NewType [arrSize]</pre>
这种类型可以掩饰一些符合类型,其中BaseType是基本类型,NewType是我们所定义的新类型,这个新定义的NewType可以像其他的基本类型那样使用。下面举个例子:
<pre lang="c" escaped="true">typedef char Array[10]; </pre>
这里的char就是基本的类型,而Array是我们新定义的类型。这里Array是一个字符型的数组类型,这个数组类型的长度为10。下面我们就可以用Array来进行一些定义了。
<pre lang="c" escaped="true"> Array array1,array2;</pre>
这里我就定义了两个Array型的数组,这两个数组都是字符型的有10个元素的数组;如果我们没有用typedef定义,那么我么就要进行下面这样的定义:
<pre lang="c" escaped="true"> char array1[10];char array2[10]。</pre>
这种形式可以应用到指针等。
这里引入typedef一个陷阱:
<pre lang="c" escaped="true">
typedef char * pstr;
int mystrcmp(pstr, pstr);
</pre>
我们知道,标准函数 strcmp()有两个"const char *"类型的参数。因此,它可能会误导人们象下面这样声明 mystrcmp():
<pre lang="c" escaped="true"> int mystrcmp(const pstr, const pstr); </pre>
用GNU的gcc和g++编译器,是会出现警告的,按照顺序,"const pstr"被解释为"char* const"(一个指向 char 的常量指针),两者表达的并非同一意思。应该按以下方式定义:
<pre lang="c" escaped="true">
typedef const char* pstr;
</pre>
函数类型的形式
<pre lang="c" escaped="true">typedef int (*PF) (const char *, const char *)</pre>
这种类似的形式
这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。这种定义的用途过会在下面以例子的形式给出。
typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并不是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。这一点对于我们理解typedef定义新类型的功能很有用。
这里引入typedef另外一个陷阱:
<pre lang="c" escaped="true"> typedef register int FAST_COUNTER; </pre>
编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register(或任何其它存储类关键字)。
3.typedef与结构体结合使用
<pre lang="c" escaped="true">
struct var {
int data1;
int data2;
char data3;
};
</pre>
这里定义一个类型var,而要定义这种类型的变量,必须这样写:struct var a;若添加typedef struct var newtype;则定义变量只需这样即可:newtype a;
typedef和结构体一般不这样使用,而是按下面这样子:
<pre lang="c" escaped="true">
typedef struct var {
int data1;
int data2;
char data3;
} newtype;
newtype a;
</pre>
在链表中更一般的形式:
<pre lang="c" escaped="true">
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext; //这里不能写为*pNode *pNext;
} *pNode;
</pre>
<pre lang="c" escaped="true">
或者 typedef struct tagNode *pNode;
struct tagNode
{
char *pItem;
pNode pNext;
};
</pre>
typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以获得最高的精度:
<pre lang="c" escaped="true">typedef long double REAL; </pre>
在不支持 long double 的机器上,该 typedef 看起来会是下面这样:
<pre lang="c" escaped="true">typedef double REAL; </pre>
并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样:
<pre lang="c" escaped="true"> typedef float REAL; </pre>
4.linux内核中typedef的例子:
<pre lang="c" escaped="true">typedef int (*PF) (const char *, const char *) </pre>
前面提到的这种类似的形式是可以简化函数的,而且便于理解。举linux内核中信号处理函数这个例子:
<pre lang="c" escaped="true"> void (*signal (int signr,void (*handler)(int))) (int) </pre>
其用typedef定义如下:
<pre lang="c" escaped="true">
typedef void sigfunc(int);
sigfunc *signal(int signr,sigfunc *handler);
</pre>
其中typedef定义了一个有一个整型参数无返回值的函数类型。void (*handler)(int)表示一个有一个整型参数无返回值的函数指针,这个指针名为handler,所以其可以用sigfunc进行说明,此时sigfunc就相当于前面的int signr中int的作用;同理这个函数也是这样。
注:对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。
<pre lang="c" escaped="true">
int *(*a[5])(int, char*);
//pFun是我们建的一个类型别名
typedef int *(*pFun)(int, char*);
//使用定义的新类型来声明对象,等价于int* (*a[5])(int, char*);
pFun a[5];
</pre>
typedef 深入剖析的更多相关文章
- TaintDroid剖析之Native方法级污点跟踪分析
1.Native方法的污点传播 在前两篇文章中我们详细分析了TaintDroid对DVM栈帧的修改,以及它是如何在修改之后的栈帧中实现DVM变量级污点跟踪的.现在我们继续分析其第二个粒度的污点跟踪—— ...
- TaintDroid剖析之DVM变量级污点跟踪(下篇)
TaintDroid剖析之DVM变量级污点跟踪(下篇)作者:简行.走位@阿里聚安全 1 回顾 在上一章节中我们详细分析了TaintDroid对DVM方法参数和方法变量的变量级污点跟踪机制,现在我们 ...
- TaintDroid深入剖析之启动篇
1 背景知识 1.1 Android平台软件动态分析现状 众所周知,在计算机领域中所有的软件分析方法都可以归为静态分析和动态分析两大类,在Android平台也不例外.而随着软件加固.混淆技术的不 ...
- STL"源码"剖析-重点知识总结
STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...
- RapidJSON 代码剖析(四):优化 Grisu
我曾经在知乎的一个答案里谈及到 V8 引擎里实现了 Grisu 算法,我先引用该文的内容简单介绍 Grisu.然后,再谈及 RapidJSON 对它做了的几个底层优化. (配图中的<Grisù& ...
- C/C++程序员应聘试题剖析(转载)
转载自:http://www.cnitblog.com/zouzheng/articles/21856.html 1.引言 本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面 ...
- C语言typedef的用法(转)
http://www.cnblogs.com/afarmer/archive/2011/05/05/2038201.html 一.基本概念剖析 int* (*a[5])(int, char*); ...
- 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析
上次的Hello world算是入门了,现在学习一些相关工具的使用 编译自动化 写好程序,首先要编译,就用gcc就好了,基本用法如下 gcc helloworld.c -o helloworld.o ...
- [ZigBee] 8、ZigBee之UART剖析·二(串口收发)
前言:上一节讲UART基本知识介绍完了,并深入剖析了一个串口发送工程,本节将进一步介绍串口收发! 1.初始化 在串口初始化部分,和上一节不同的地方是: 51 U0CSR |= 0x40; //允许接收 ...
随机推荐
- URAL 1183 Brackets Sequence(DP)
题目链接 题意 : 给你一串由括号组成的串,让你添加最少的括号使该串匹配. 思路 : 黑书上的DP.dp[i][j] = min{dp[i+1][j-1] (sh[i] == sh[j]),dp[i] ...
- linux查找有用日志常用技巧
对于高级测试人员来说.需要有快速定位问题的能力,而查看有效的日志就是其中有效的方法之一,然而服务器上的日志多如牛毛,如何快速从中找出所需信息非常重要,以下是我在工作中用到的查找日志的简单命令,希望对大 ...
- iis 重启 (三种方法)
iis 重启 (三种方法) WINDOWS提供WEB服务的IIS有时候会出现访问过大导致网站打不开,这时重启IIS是最好的选择. 方法/步骤 1 1.界面操作 打开“控制面板”->“管理工具”- ...
- iOS 开发--添加工程
文/Bison(简书作者)原文链接:http://www.jianshu.com/p/dd71e15df5d0著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 第一部分,配置项目 在此只 ...
- LoadRunner8 安装步骤
一.介绍 LoadRunner,是一种预测系统行为和性能的负载测试工具.通过以模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner能够对整个企业架构进行测试.企业使用L ...
- 常见的css3缩放效果
transform的属性scale(x,y) 对元素进行缩放,x表示水平方向缩放倍数,y表示垂直方向的缩放倍数,y是可选参数,不设置,则表示两个方向的倍数是一样的,基点一样在元素的中心位置. 还有单向 ...
- SSIS ->> Logging
SSIS提供了Event Handler之外的另一种方法捕捉Event和获取需要的信息,这种方法是Logging.SSIS的Logging针对不同的组件可以提供比Event Handler更多的Eve ...
- PV UV
定义 PV: Page View 页面浏览量或点击量,用户每次刷新即被计算一次. UV: Unique Visitor 就是有多少个IP数量.就是指的有多少人在访问你的店.每个人用的电脑 ...
- 局部敏感哈希Locality Sensitive Hashing(LSH)之随机投影法
1. 概述 LSH是由文献[1]提出的一种用于高效求解最近邻搜索问题的Hash算法.LSH算法的基本思想是利用一个hash函数把集合中的元素映射成hash值,使得相似度越高的元素hash值相等的概率也 ...
- Data Base sqlServer基础知识
sqlServer 基础知识 大纲 创建数据库 1 创建表 2 备份表 3 删除表 4 修改表 5 查询出重复的数据 6 增删改查 7 添加约束 8 分页存储过程 9 排序 10 类型转换 11 ...