typedef 深入剖析

typedef是一个我们常常会用到的关键字,而这个关键字有许多陷阱或者说许多不为我们深入理解的地方。很多书上都是很简单地一笔代过,并没有真正地让我们理解这个关键字。本文对其进行详细地说明。
综合网络上找到的资料对其进行分析,这其中会涉及到一些其他c方面的内容(比如指针,指向函数的指针,编译时候数据类型未定义与完全定义知识等等),看到这些内容的时候大家可以忽略,这个重点是在typedef。
好了,不说那么多开始吧。
 
<h4>typedef的定义</h4>
&nbsp;
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>

转载于:https://www.cnblogs.com/liweilijie/p/4984199.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262468.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jquery数组(操作数组元素)

HTML&#xff1a; <h3>数组map方法</h3> <div id"show4"></div> jquery&#xff1a; $(document).ready(function(){var animals [dog,cat,tiger,pig,bird]; animals $.map(animals, function(n,i){return i.This is n;});$(#show4).h…

系统分析师考试大纲

一、考试说明 1.考试要求&#xff1a;  &#xff08;1&#xff09;具有系统工程的基础知识&#xff1b;  &#xff08;2&#xff09;掌握开发信息系统的综合技术知识&#xff08;硬件、软件、网络、数据库&#xff09;&#xff1b;  &#xff08;3&#xff09;熟悉企业和…

configure project qt,如何为Qt Framework配置CLion IDE?

How to configure CLion IDE for Qt Framework?Is this IDE compatible with Qt, or are there other IDEs compatible with Qt?I just want to try to use something else than Qt Creator.解决方案I was as desperate as you, until I read this Quora discussion.It worke…

PostgreSQL入门篇学习笔记(七)

2019独角兽企业重金招聘Python工程师标准>>> pg数据库&#xff1a;能提供读写全功能的服务器称为Primary database或者master database。若备份服务器在接受主数据库同步数据和应用同步数据库时&#xff0c;不能提供只读的服务&#xff0c;则该备份数据库称之为warm…

Qt的元对象(Meta-Object)系统简介(转)

Qt的元对象系统基于如下三件事情&#xff1a; 1.类&#xff1a;QObject&#xff0c;为所有需要利用原对象系统的对象提供了一个基类。 2.宏&#xff1a;Q_OBJECT&#xff0c;通常可以声明在类的私有段中&#xff0c;让该类可以使用元对象的特性&#xff0c;比如动态属性&#x…

回归测试的策略

回归测试是贯穿在整个测试的各个阶段的一个测试活动。它的目的是检验已经被发现的缺陷有没有被正确的修改和修改过程中有没有引发新的缺陷。软件在测试或者其他活动中发现的缺陷经过修改后&#xff0c;都要进行回归测试的验证。在做回归测试的时候可以采用不同的策略。 策 略&a…

Meteor创建示例项目 Simple-todos

2019独角兽企业重金招聘Python工程师标准>>> 本笔记&#xff0c;基于Windows环境。 1、Meteor提供了一些示例项目供开发者参考&#xff0c;打开命令行&#xff0c;输入meteor create --list 可以查看提供了哪些示例项目 2、通过meteor create --example <project…

RHEL6下squid代理之正向代理

Squid cache&#xff08;简称为Squid&#xff09;是一个流行的自由软件&#xff08;GNU通用公共许可证&#xff09;的代理服务器和Web缓存服务器。Squid有广泛的用途&#xff0c;从作为网页服务器的前置cache服务器缓存相关请求来提高Web服务器的速度&#xff0c;到为一组人共享…

ASP.NET 使用 X509Certificate2 系统找不到指定的文件

经过虚拟机里面每个用户权限的剥离和对比&#xff0c;最后发现必须要USER的读取权限才能访问证书&#xff01;转载于:https://www.cnblogs.com/zjoch/archive/2009/06/19/1506399.html

跨平台Markdown编辑软件Typora mac功能介绍

Typora mac是一款跨平台的Markdown编辑器&#xff0c;支持Windows、MacOS和Linux操作系统。它具有实时预览功能&#xff0c;能够自动将Markdown文本转换为漂亮的排版效果&#xff0c;让用户专注于写作内容而不必关心格式调整。Typora Mac版除了支持常见的Markdown语法外&#x…

linux精简、备份还原、iso文件、批量安装?

最近小组需要批量自动部署一批机器&#xff0c;把Linux和自己的应用一次批量安装完&#xff0c;每次克隆硬件有点麻烦&#xff0c;因此查了一下相关的资料&#xff0c;看那种方案最好&#xff0c;整理如下。不过没有找到类似windows那样的ghost盘安装的形式&#xff0c;不知网友…

内存总结

(1)lru_file_repage: 当 lru_file_repage 可调参数设置为 1 时&#xff0c;AIX 内核使用这个重新分页信息来确定是否仅选择非计算性的分页进行操作、或者选择计算性的和非计算性的分页进行操作。如果计算性分页的重新分页速度比非计算性分页的重新分页速度高&#xff0c;那么…

如何解决 SQL Server 安装程序中的 COM+ 系统配置检查失败问题

转载自&#xff1a;http://technet.microsoft.com/zh-cn/library/ms143690(SQL.90).aspxSQL Server 2005 联机丛书&#xff08;2008 年 11 月&#xff09;如何解决 SQL Server 安装程序中的 COM 系统配置检查失败问题Microsoft SQL Server 2005 安装程序检查 COM 是否已正确配置…

mysql decimal(6_MySQL(六) decimal数据默认处理

create table decimal_test(id int auto_increment PRIMARY key,score decimal(5,2) -- 取值范围是 -999.99 到 999.99);decimal(M,D)M整数位小数位-- 整数的位数必须小于等于m-d&#xff0c;不然报错。小数的位数可以大于d位。多出d位时会做四舍五入&#xff0c;截取到d位。--…

读取记事本内容,自动发布到新浪微博

想把自己博客上的内容同步到新浪微博上&#xff0c;虽然新浪微博已经提供了关联博客的功能&#xff0c;但那仅限于新发布的微博内容。 手工一条条发布呢&#xff0c;实在枯燥&#xff0c;就想到新浪微博的api接口&#xff0c;结果第一个版本现在已经停止申请了&#xff0c;第二…

Objective-C Runtime 运行时之五:协议与分类

Objective-C中的分类允许我们通过给一个类添加方法来扩充它&#xff08;但是通过category不能添加新的实例变量&#xff09;&#xff0c;并且我们不需要访问类中的代码就可以做到。 Objective-C中的协议是普遍存在的接口定义方式&#xff0c;即在一个类中通过protocol定义接口&…

sqlserver中在建立与服务器的连接时出错

解决&#xff1a;步骤1&#xff1a;在SQLServer 实例上启用远程连接1.指向“开始->程序->Microsoft SQL Server 2005->配置工具->SQL Server 外围应用配置器”2.在“SQL Server 2005 外围应用配置器”页, 单击“服务和连接的外围应用配置器”3.然后单击展开“数据库…

mysql 热备 windows_windows下mysql热备

A: mysql> Grant replication slave on *.* to backup10.16.0.233 identified by 1234; *结尾分号要打代表确认B: mysql> Grant replication slave on *.* to backup10.16.0.231 identified by 1234&#xff1b;注&#xff1a; (1). mysql> Grant 权限 on *.* to 用户…

【转】PB实现在通知区域添加图标

“为应用程序在任务栏通知区域加个图标&#xff0c;按最小化控制菜单后隐藏窗口&#xff0c;单击通知区域内的图标恢复并显示窗口&#xff0c;右击通知区域内的图标弹出快捷方式菜单”&#xff0c;已成为时下程序设计上的一个时髦主题&#xff0c;有不少文章介绍了如何实现&…

[LeetCode]题解(python):058-Length of Last Word

题目来源&#xff1a; https://leetcode.com/problems/length-of-last-word/ 题意分析&#xff1a; 给出只包括大小写和空格的字符&#xff0c;输出最后一个单词的长度。 题目思路&#xff1a; 从最后一个字符开始搜索&#xff0c;如果字符非空格&#xff0c;则往前推一位&…