typedef用法剖析

     typedef 声明,简称 typedef,为现有类型创建一个新的名字。比如人们常常使用 typedef 来编写更美观和可读的代码。所谓美观,意指 typedef 能隐藏笨拙的语法构造以及平台相关的数据类型,从而增强可移植性和以及未来的可维护性。本文下面将竭尽全力来揭示 typedef 强大功能以及如何避免一些常见的陷阱。

      如何创建平台无关的数据类型,隐藏笨拙且难以理解的语法?

      使用 typedefs 为现有类型创建同义字。

    定义易于记忆的类型名
      typedef 使用最多的地方是创建易于记忆的类型名,用它来归档程序员的意图。类型出现在所声明的变量名字中,位于 ''typedef'' 关键字右边。例如:

    typedef int size;
      此声明定义了一个 int 的同义字,名字为 size。注意 typedef 并不创建新的类型。它仅仅为现有类型添加一个同义字。你可以在任何需要 int 的上下文中使用 size:

    void measure(size * psz);
    size array[4];
    size len = file.getlength();
    std::vector <size> vs;
      typedef 还可以掩饰符合类型,如指针和数组。例如,你不用象下面这样重复定义有 81 个字符元素的数组:

    char line[81];
    char text[81];
    定义一个 typedef,每当要用到相同类型和大小的数组时,可以这样:

    typedef char Line[81];
    Line text, secondline;
    getline(text);
    同样,可以象下面这样隐藏指针语法:

    typedef char * pstr;
    int mystrcmp(pstr, pstr);
      这里将带我们到达第一个 typedef 陷阱。标准函数 strcmp()有两个‘const char *'类型的参数。因此,它可能会误导人们象下面这样声明 mystrcmp():

    int mystrcmp(const pstr, const pstr);
      这是错误的,按照顺序,‘const pstr'被解释为‘char * const'(一个指向 char 的常量指针),而不是‘const char *'(指向常量 char 的指针)。这个问题很容易解决:

    typedef const char * cpstr;
    int mystrcmp(cpstr, cpstr); // 现在是正确的
    记住:不管什么时候,只要为指针声明 typedef,那么都要在最终的 typedef 名称中加一个 const,以使得该指针本身是常量,而不是对象。

    代码简化
      上面讨论的 typedef 行为有点像 #define 宏,用其实际类型替代同义字。不同点是 typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。例如:

    typedef int (*PF) (const char *, const char *);
      这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:
 PF Register(PF pf);
      Register() 的参数是一个 PF 类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我们是如何实现这个声明的:

    int (*Register (int (*pf)(const char *, const char *)))
    (const char *, const char *);
      很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,而是一种必需。持怀疑态度的人可能会问:"OK,有人还会写这样的代码吗?",快速浏览一下揭示 signal()函数的头文件 <csinal>,一个有同样接口的函数。

    typedef 和存储类关键字(storage class specifier)
      这种说法是不是有点令人惊讶,typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。下面将带到第二个陷阱:

    typedef register int FAST_COUNTER; // 错误
      编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register(或任何其它存储类关键字)。

    促进跨平台开发
      typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以i获得最高的精度:

    typedef long double REAL;
    在不支持 long double 的机器上,该 typedef 看起来会是下面这样:

    typedef double REAL;
    并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样: 、

    typedef float REAL;
      你不用对源代码做任何修改,便可以在每一种平台上编译这个使用 REAL 类型的应用程序。唯一要改的是 typedef 本身。在大多数情况下,甚至这个微小的变动完全都可以通过奇妙的条件编译来自动实现。不是吗? 标准库广泛地使用 typedef 来创建这样的平台无关类型:size_t,ptrdiff 和 fpos_t 就是其中的例子。此外,象 std::string 和 std::ofstream 这样的 typedef 还隐藏了长长的,难以理解的模板特化语法,例如:basic_string<char, char_traits<char>,allocator<char>> 和 basic_ofstream<char, char_traits<char>>。

 

 

 

 

    作者简介
      Danny Kalev 是一名通过认证的系统分析师,专攻 C++ 和形式语言理论的软件工程师。1997 年到 2000 年期间,他是 C++ 标准委员会成员。最近他以优异成绩完成了他在普通语言学研究方面的硕士论文。 业余时间他喜欢听古典音乐,阅读维多利亚时期的文学作品,研究 Hittite、Basque 和 Irish Gaelic 这样的自然语言。其它兴趣包括考古和地理。Danny 时常到一些 C++ 论坛并定期为不同的 C++ 网站和杂志撰写文章。他还在教育机构讲授程序设计语言和应用语言课程。

 

注:这篇经典的文章选自C&C++开发人员论坛,感谢该论坛贴出Danny Kalev的这篇文章!!!让我有幸享用大师的智慧!(hain)

 

 

<think>好的,我现在需要帮助用户理解C语言typedefstruct的用法,以及如何用它来定义PID参数结构体。用户之前已经提问过关于PID头文件的问题,现在他们想更深入地了解typedef struct的具体应用。首先,我需要回顾用户提供的引用内容。引用[2]提到typedef用于为结构体定义别名,简化代码和提高可读性。引用[3]中的例子展示了结构体数组的用法,可能和PID参数的结构体定义相关。用户之前的代码中,有多个结构体定义,比如pidInit_t、pidParam_t等,都是通过typedefstruct创建的。 接下来,我需要解释typedef struct的基本用法。通常,在C语言中,定义结构体需要使用struct关键字,但使用typedef可以为结构体创建一个别名,这样在声明变量时就不需要重复写struct了。例如,structPoint和typedef后的POINT,用户可以直接用POINT声明变量,这样更简洁。 然后,结合PID控制的例子,用户代码中的pidInit_t结构体包含kp、ki、kd三个浮点数成员,用来表示PID的参数。通过typedef struct,他们为这个结构体创建了别名,方便后续使用。比如在configParam_t结构体中,使用了pidParam_t等别名,使得代码更易读。需要指出typedefstruct在代码中的作用:简化类型名称、提高可移植性、增强可读性。例如,如果以后需要修改结构体的名称,只需修改typedef部分,而不必改动所有使用该结构体的地方。这在大型项目中尤其重要。此外,用户之前的代码中有嵌套结构体的情况,比如pidParam_t包含roll、pitch、yaw三个pidInit_t结构体。这说明typedefstruct也可以用于创建嵌套的结构体类型,使得复杂的数据结构更清晰。 还需要注意,用户可能混淆结构体定义和别名声明的位置。例如,正确的写法是将结构体定义和typedef结合在一起,如typedefstruct {... }pidInit_t;,这样pidInit_t就是一个类型别名了。 最后,生成相关问题时要围绕typedefstruct的用法、结构体设计、PID参数定义等方面,确保问题与用户的学习路径相关,帮助他们进一步巩固知识。</think>### C语言typedef struct用法详解 #### 一、基本语法形式 ```c typedef struct [原结构体名] { // 成员变量 } 新类型名; ``` - `struct`关键字声明结构体类型 - `typedef`为结构体创建类型别名 - 新类型名遵循C语言变量命名规则 #### 二、典型应用场景 1. **简化声明** 传统方式需带`struct`关键字: ```c struct PIDParams { /*...*/ }; struct PIDParams controller; ``` typedef方式可直接使用别名: ```c typedef struct { /*...*/ } PIDParams; PIDParams controller; // 无需struct前缀[^2] 2. **嵌套结构体定义** 在PID控制系统中常见多层结构: ```c typedef struct { float kp, ki, kd; } PIDGains; typedef struct { PIDGains roll; // 横滚轴参数 PIDGains pitch; // 俯仰轴参数 PIDGains yaw; // 偏航轴参数 } FlightControllerParams; ``` 3. **结构体数组应用** 结合引用[3]的结构体数组用法: ```c typedef struct { float kp, ki, kd; } MotorPID; MotorPID motor_params[4]; // 四电机PID参数数组 ``` #### 三、PID参数结构体实现 ```c /* PID基础参数结构体 */ typedef struct { float kp; // 比例系数 float ki; // 积分系数 float kd; // 微分系数 } PID_Coefficients; /* 完整PID控制器结构体 */ typedef struct { PID_Coefficients params; // 控制参数 float integral; // 积分项累积值 $$ \int e(t)dt $$ float prev_error; // 前次误差值 $$ e(t-1) $$ float output_limit; // 输出限幅值 } PID_Controller; ``` #### 四、设计优势分析 1. **类型安全性** 编译器会检查类型匹配,避免误用其他结构体 2. **代码可维护性** 修改结构体定义只需调整typedef部分,例如: ```c // 原定义 typedef struct { float kp, ki, kd; } PID_Coefficients; // 修改后增加积分限幅 typedef struct { float kp, ki, kd; float integral_max; // 新增积分限幅 } PID_Coefficients; ``` 3. **内存布局优化** 结构体成员按内存对齐原则排列,例如: ```c typedef struct { float a; // 4 bytes double b; // 8 bytes (可能产生4字节填充) int c; // 4 bytes } OptimizedStruct; // 总大小可能为20 bytes ``` #### 五、工程实践建议 1. **命名规范** 推荐使用`_t`后缀表示类型定义,如`pid_params_t` 2. **参数初始化** 使用复合字面量初始化: ```c PID_Coefficients coeff = { .kp = 2.5f, .ki = 0.1f, .kd = 0.05f }; ``` 3. **跨平台兼容性** 使用标准类型定义确保可移植性: ```c #include <stdint.h> typedef struct { int32_t sensor_id; float calibration; } DeviceInfo; ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值