C语言中typedef的用法

 2024-02-03 04:04:33  阅读 0

整数a[5];

数组指针(指向数组)的声明如下:

int (*pa)[5];

可以这样使用:

pa = &a; // 赋值()操作

int i = (*pa)[2]; // 将 a[2] 赋给 i;

2、有了以上基础,我们一开始就可以对付三纸老虎了! :) 这时候就需要回顾一下各个算子的优先级和组合顺序了。 顺便看看这本书就够了。

#1: int* (*a[5])(int, char*);

首先,我们看到标识符名称a。 “[]”的优先级大于“*”,所以a和“[5]”先组合。 所以 a 是一个数组。 该数组有 5 个元素,每个元素都是一个指针。

指针指向“(int, char*)”,是的,它指向一个函数。 函数参数为“int,char*”,返回值为“int*”。 完了,我们杀死了第一只纸老虎。 :)

#2: void (*b[10]) (void (*)());

b 是一个数组。 该数组有 10 个元素。 每个元素都是一个指针。 指针指向一个函数。 函数参数为“void (*)()”[注1],返回值为“void”。 完全的!

注1:该参数也是一个指针,指向一个函数。 函数参数为空,返回值为“void”。

#3: (*)()(*pa)[9];

pa是一个指针,它指向一个数组。 这个数组有9个元素,每个元素是“(*)()”【即指向函数的指针,函数参数为空,返回值为“

-------------------------------------------------- -------------

#1: int* (*a[5])(int, char*);

int* (*PF)(int, char*);//PF是类型别名【注2】。

PF a[5];//效果与int*(*a[5])(int, char*);相同!

注2:很多初学者只知道char* pchar; 但他们对其他用途不太了解。 Blaha总结了用法:“创建类型别名的方法很简单,将变量名替换为传统变量声明表达式中的类型名,然后在语句开头添加关键字。”

#2: void (*b[10])(void (*)());

无效(*pfv)();

无效(*)(pfv);

b[10]; //与void (*b[10]) (void (*)()) 效果相同!

#3。 (*)()(*pa)[9];

(*PF)();

PF (*PA)[9];

帕帕; //与doube(*)()(*pa)[9];效果相同!

3.const以及在类型声明中的位置。

这里我只说const,是一样的! [注3]

注3:顾名思义,修改量是一个容易改变且不稳定的量。 它可能会在未知的时间被其他线程、操作系统、硬件等更改。

所以它是保存在内存中的,每次访问时只能从内存中读取。 它不能被编译器优化并放置在内部寄存器中。

在类型声明中,const 用于修饰常量。 我们一般这样使用:const在前面:

常量整型; //int 是常量

const char*;//char 是 const

字符*常量; //* (指针)是 const

常量字符*常量; //char 和 * 都是 const

对于初学者来说,const char* 和 char* const 很容易混淆。 您需要时间来适应它。 上面的语句有一个等效的符号:const如下:

整型常量; //int 是常量

char const*;//char 是 const

字符*常量; //* (指针)是 const

字符常量*常量; //char 和 * 都是 const

第一次你可能会不习惯,但如果新事物是好的,我们为什么要拒​​绝它呢? :) const 后面有两个好处:

A. const 修饰的类型与它之前的类型完全相同。 如果这个好处没有吸引你,那么请阅读下一篇!

B. 我们经常使用类型别名定义。 例如char* pchar,如果用const修饰,

当const在前面时,它是const pchar。 你会认为它是const char*,但你错了。 它的真正含义是char* const。

你不感到惊讶吗! 但如果最后用const写的话,意思是不会改变的。 如果你不相信我,就试试吧!

然而,实际项目中命名的一致性更为重要。 你应该能够适应这两种情况,并且能够轻松切换公司习惯,

商业利润始终是您的首要任务! 但是,当开始一个新项目时,您可以考虑先在后一种习惯用法中使用const。

2. 声明有助于创建与平台无关的类型,甚至可以隐藏复杂且难以理解的语法。

无论如何,使用它可以给代码带来意想不到的好处。 通过本文,您可以学习如何避免缺陷并使代码更加健壮。

简而言之,声明为现有类型创建一个新名称。 例如,人们经常用它来编写更美观、可读的代码。

我所说的美观,是指隐藏笨拙的语法结构和特定于平台的数据类型,从而增强可移植性和未来的可维护性。

本文将尽力揭示强大的功能以及如何避免一些常见的陷阱,如何创建与平台无关的数据类型,以及隐藏笨拙且难以理解的语法。

最常见的用例是创建易于记住的类型名称来记录程序员的意图。 类型出现在关键字右侧声明的变量名称中。

例如:int大小;

该声明定义了一个名为 size 的 int 同义词。 请注意,没有创建新类型。 它只是为现有类型添加同义词。

您可以在任何需要 int 的上下文中使用 size:

无效(大小* psz);

大小数组[4];

大小 len = 文件。();

复合类型(例如指针和数组)也可以被屏蔽。 例如,您不需要像这样重复定义具有 81 个字符元素的数组:

字符行[81]; 字符文本[81];

每当您想要使用相同类型和大小的数组时,就定义一个数组,如下所示:

字符行[81];

行文本,;

(文本);

同样,指针语法可以隐藏如下:

字符 * pstr;

int(pstr,pstr);

这给我们带来了第一个陷阱。 标准函数()有两个const char *类型的参数。 因此,如下声明可能会误导人们:

int(常量 pstr,常量 pstr);

这是错误的,实际上const pstr被编译器解释为char * const(指向char的常量指针),而不是const char *(指向常量char的指针)。

这个问题很容易解决:

const char * cpstr;

int (cpstr, cpstr);

上面讨论的行为有点像 # 宏,用同义词替换其实际类型。差异在编译时解释

,从而使编译器能够处理超出预处理器能力的文本替换。 例如:

int (*PF) (const char *, const char *);

此声明引入了 PF 类型作为函数指针的同义词,该函数指针采用 const char * 类型的两个参数和 int 类型的返回值。 如果您想使用以下形式的函数声明,这一点至关重要:

PF(PF pf);

()的参数是一个PF类型的回调函数,返回一个签名与之前注册的名字相同的函数的地址。 深吸一口气。 下面我展示一下如果不使用这个语句我们如何实现:

int (* (int (*pf)(const char *, const char *))) (const char *, const char *);

很少有程序员理解它的含义,更不用说这种复杂的代码所带来的错误风险了。 显然,使用在这里并不是一种特权,

但有必要。 就像auto、、、和一样,是一个存储类关键字。

这并不意味着它实际上会影响对象的存储特性; 它只是意味着就语句结构而言,声明看起来像相同类型的变量声明。

这给我们带来了第二个陷阱:

整数; // 错误编译失败

问题是声明中不能有多个存储类关键字。 因为该符号已经占据了存储类关键字位置,

不能在声明(或任何其他存储类关键字)中使用。 还有另一个重要的用途,就是定义与机器无关的类型。

例如,您可以定义一个名为 REAL 的浮点类型,它可以在目标机器上实现最高精度:

长实数;

在不支持 long 的机器上,它看起来像这样:

真实的;

而且,在甚至不支持它的机器上,它看起来像这样:

浮动实数;

您可以在每个平台上编译此 REAL 类型应用程序,而无需对源代码进行任何更改。 唯一要改变的就是它自己。

在大多数情况下,即使是很小的更改也可以通过条件编译的魔力完全自动化。 不是吗?

标准库广泛用于创建此类与平台无关的类型: 、 和 是示例。

此外,像 std:: 和 std:: 之类的东西隐藏了冗长且难以理解的模板专业化语法。

例如:、> 和 >。

使用一个:

为类型定义别名而不仅仅是简单的宏替换。 可用于同时声明多个指针类型的对象。 例如:

字符* pa, pb; // 这大部分不符合我们的意图。 它仅声明一个指向字符变量的指针。

// 和一个字符变量;

法语tcftef_法语construction_c语言typedef的用法详解

以下是可能的:

字符*PCHAR; // 一般使用大写字母

PCHAR pa,pb; // 可行,同时声明两个指向字符变量的指针

虽然:

字符 *pa, *pb;

也是可行的,但是比较没用,而且形式直观,特别是在需要大量指针的地方。 该方法比较省事。

使用两个:

在旧的 C 代码中使用(我没有具体检查它有多旧),它有帮助。 前面的代码中,声明新对象时,必须带上,即形式:结构体名对象名,如:

整数x;

整数y;

};

p1;

在C++中,可以直接写:结构体名对象名,即:

p1;

估计有人觉得频繁写一个太麻烦,所以就发明了:

整数x;

整数y;

}观点;

点 p1; // 这样就比原来的方法少写了一个字,更省事,尤其是大量使用的时候。

或许,在C++中,这种用处并不是很大,但是了解它对于掌握旧代码还是有帮助的。 毕竟,我们可能会遇到项目早期遗留下来的代码。

使用三:

用于定义与平台无关的类型。

例如,定义一个名为 REAL 的浮点类型。 在目标平台一上,让它代表最高精度的类型:

长实数;

在不支持long的平台2上,改为:

真实的;

在甚至不支持的平台3上,更改为:

浮动实数;

也就是说,涉及到跨平台的时候,你只需要改变它,而不需要对其他源代码进行任何修改。

例如,标准库广泛使用这种技术。

另外,由于它定义了类型的新别名,而不是简单的字符串替换,因此它比宏更健壮(尽管有时可以使用宏来完成上述目的)。

使用四:

为复杂声明定义一个新的简单别名。 方法是:将原声明中的部分复杂声明逐渐替换为别名,以此类推,保留变量名部分直至最后替换,得到的就是原声明的简化版本。 例子:

1、原语句:int *(*a[5])(int, char*);

变量名为a,只需将a替换为新的别名pFun即可:

int *(*pFun)(int, char*);

标签: char const 指针

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码