在C 与 C++ 中的 typedef 和 struct 命名空间中,其中一条评论似乎暗示暴露一些struct foo
比使用 typedef 更可取...
typedef struct foo foo;
...然后在整个 API 中使用foo
而不是使用。struct foo
后一种变体有什么缺点吗?
在C 与 C++ 中的 typedef 和 struct 命名空间中,其中一条评论似乎暗示暴露一些struct foo
比使用 typedef 更可取...
typedef struct foo foo;
...然后在整个 API 中使用foo
而不是使用。struct foo
后一种变体有什么缺点吗?
唯一的缺点(*)是它隐藏了foo
一个结构的事实,而不是某些内置类型的别名。
注意(*):这是否对您不利,这取决于您的口味。
这取决于你有多喜欢这个词struct
。如果你觉得你的程序会通过自由洒struct that
和struct tother
(当然你不能struct this
在 C++ 中)使你的程序更清晰,那么一定要使用这个struct
版本。
就个人而言,我不认为重复struct
提供任何好处,我很高兴只使用这个typedef
名字。而且因为 C++typedef struct xyz xyz;
自动有效地提供了声明(它不是很准确,尤其是因为你可以用 C++ 显式编写它,但它足够接近,你可能不必担心它),我认为它是完美的在 C 中使用相同的东西是有意义的。C 编译器对此很满意,所以我通常使用typedef struct tag tag;
然后在需要的地方使用tag
和。tag *
如需另一种但完全站得住脚的观点,请阅读Linux 内核编码风格指南。
请注意,C2011 允许您重新定义 a typedef
,只要它别名相同的类型:
ISO/IEC 9899:2011 §6.7 声明
语义
¶5 声明指定一组标识符的解释和属性。标识符的定义是该标识符的声明:
— 对于一个对象,导致为该对象保留存储空间;
— 对于函数,包括函数体;119)
— 对于枚举常量,是标识符的(唯一)声明;
— 对于 typedef 名称,是标识符的第一个(或唯一一个)声明。
与 C99 相比,这是不可能的:
语义
¶5 声明指定一组标识符的解释和属性。标识符的定义是该标识符的声明:
— 对于一个对象,导致为该对象保留存储空间;
— 对于函数,包括函数体;98)
— 对于枚举常量或 typedef 名称,是标识符的(唯一)声明。
只要您保持一致,这就会简化类型定义的创建(但前提是您在与您相关的每个平台上都有足够兼容的 C2011 编译器)。
关于是否 typedef 结构类型:
这里有一些意见(都反对 typedefing 结构):
来自 OpenBSD 风格指南:
“避免对结构类型使用 typedef。这使得应用程序不可能不透明地使用指向这种结构的指针,这在使用普通结构标记时既可行又有益。”
从 Linux 内核编码风格:
“将 typedef 用于结构和指针是错误的。”
来自 Peter Van der Linden 的 Expert C Programming:
“不要为结构体的 typedefs 烦恼。他们所做的只是省去你写“结构体”这个词的麻烦,这是一个你可能不应该隐藏的线索。
这或多或少是一个品味问题。
通过仅声明一个struct
标签,该名称也可用于同一范围内的变量、函数或枚举器(如果您喜欢混淆,甚至可以是另一种类型);并且用户必须写这个词struct
,这使得他们的代码更加明确。
通过还声明类型名称,您可以允许人们在不想键入struct
时不键入。
我在另一个问题中的评论是指与结构标记同名的指针类型的声明:
typedef struct foo * foo;
从风格上讲,这有点令人不快,因为它隐藏了它是指针的事实。这隐藏了它是一个指针的事实;在那个问题的上下文中,这可能很好,这是由 API 定义的不透明类型,但在我看来,对于非透明类型来说是相当粗鲁的。它还破坏了与 C++ 的兼容性。在那种语言中,这样的声明是无效的,因为struct foo
引入foo
了当前命名空间而不是单独的标记空间,并防止在该命名空间中声明任何其他具有相同名称的类型。
只要坚持命名约定,你就会没事的。
typedef struct
{
//...
} t_mytype;
//...
t_mytype thing;
这样你就会知道它是一个自定义类型。至于它是一个结构,只需使用显式名称而不是真正使用t_mytype
反对 typedef 的另一个论点是它编写干净的标头的难度。让我们看一个标题的例子:
#ifndef HEADER_H
#define HEADER_H
#include "s.h"
void f(struct s *);
#endif
这个标题可以改进。确实,struct s
不需要定义。所以可以写成:
#ifndef HEADER_H
#define HEADER_H
struct s;
void f(struct s *);
#endif
因此,用户可以使用struct s
不透明的结构,我们可以保持"s.h"
私有。
让我们做同样的事情,但使用typedef
:
#ifndef HEADER_H
#define HEADER_H
typedef struct s s_t;
void f(s_t *);
#endif
该行将typedef struct s s_t
出现在每个要使用的标题中,s_t *
我不喜欢冗余代码。有多种方法可以避免这种情况,但最简单的可能是摆脱 typedef。