简体   繁体   English

为什么是“typedef struct foo foo;” 认为有害?

[英]Why is “typedef struct foo foo;” considered harmful?

In typedef and struct namespaces in C vs C++ , one of the comments seems to imply that exposing some struct foo is preferable to using typedef along the lines of...C 与 C++ 中的 typedef 和 struct 命名空间中,其中一条注释似乎暗示暴露一些struct foo比使用 typedef 更可取...

typedef struct foo foo;

...and then using foo instead of struct foo throughout the API. ...然后在整个 API 中使用foo而不是struct foo

Are there any downsides to the latter variant?后一种变体有什么缺点吗?

The only downside(*) is that it hides the fact that foo is a struct, and not an alias for some builtin type.唯一的缺点 (*) 是它隐藏了foo是结构体而不是某些内置类型的别名的事实。

Note(*): it's matter of taste whether this is a downside for you.注意(*):这是否对您不利是品味问题。

  • It's good for total opaqueness (see the first comment below).这有利于完全不透明(请参阅下面的第一条评论)。
  • To see why some people think this is a downside, check the linux kernel coding style (typedefs chapter).要了解为什么有些人认为这是一个缺点,请查看linux 内核编码风格(typedefs 章节)。

It depends how much you like the word struct .这取决于您有多喜欢struct一词。 If you feel your program will be made clearer by a liberal sprinkling of struct that and struct tother (you can't have struct this in C++, of course), then by all means use the struct version.如果您觉得通过struct tother struct thatstruct tother您的程序更加清晰(当然,您不能在 C++ 中使用struct this ),那么请struct tother使用struct版本。

Personally, I don't think that repeating struct provides any benefit and I'm happy to use just the typedef name.就我个人而言,我认为重复struct没有任何好处,我很高兴只使用typedef名称。 And because C++ effectively provides the typedef struct xyz xyz;并且因为 C++ 有效地提供了typedef struct xyz xyz; declaration automatically (it isn't quite accurate, not least because you can explicitly write that in C++, but it is close enough that you probably don't have to worry about it), I think it makes perfect sense to use the same in C. The C compiler is happy with it, so I normally use typedef struct tag tag;自动声明(它不太准确,尤其是因为您可以在 C++ 中明确地编写它,但它足够接近,您可能不必担心),我认为在C. C 编译器对它很满意,所以我通常使用typedef struct tag tag; and then use tag and tag * where needed.然后在需要的地方使用tagtag *


For an alternative but wholly tenable view, read the Linux kernel coding style guide.对于另一种但完全站得住脚的观点,请阅读Linux 内核编码风格指南。


Note that C2011 allows you to redefine a typedef as long as it aliases the same type:请注意,C2011 允许您重新定义typedef ,只要它具有相同类型的别名:

ISO/IEC 9899:2011 §6.7 Declarations ISO/IEC 9899:2011 §6.7 声明

Semantics语义

¶5 A declaration specifies the interpretation and attributes of a set of identifiers. ¶5 声明指定了一组标识符的解释和属性。 A definition of an identifier is a declaration for that identifier that:标识符的定义是对该标识符的声明:

— for an object, causes storage to be reserved for that object; — 对于一个对象,导致为该对象保留存储空间;

— for a function, includes the function body; ——对于函数,包括函数体; 119) 119)

— for an enumeration constant, is the (only) declaration of the identifier; — 对于枚举常量,是标识符的(唯一)声明;

— for a typedef name, is the first (or only) declaration of the identifier. — 对于 typedef 名称,是标识符的第一个(或唯一)声明。

Contrast with C99 where this was not possible:与 C99 相比,这是不可能的:

ISO/IEC 9899:1999 §6.7 Declarations ISO/IEC 9899:1999 §6.7 声明

Semantics语义

¶5 A declaration specifies the interpretation and attributes of a set of identifiers. ¶5 声明指定了一组标识符的解释和属性。 A definition of an identifier is a declaration for that identifier that:标识符的定义是对该标识符的声明:

— for an object, causes storage to be reserved for that object; — 对于一个对象,导致为该对象保留存储空间;

— for a function, includes the function body; ——对于函数,包括函数体; 98) 98)

— for an enumeration constant or typedef name, is the (only) declaration of the identifier. — 对于枚举常量或 typedef 名称,是标识符的(唯一)声明。

This simplifies the creation of type definitions as long as you're consistent (but only if you have a sufficiently compatible C2011 compiler on each platform of relevance to you).只要您保持一致(但前提是您在与您相关的每个平台上都有足够兼容的 C2011 编译器),这会简化类型定义的创建。

On whether or not to typedef structure types:关于是否要 typedef 结构类型:

Here is some opinions around (all against typedefing structures):以下是一些意见(都反对 typedefing 结构):

From OpenBSD style guide:来自 OpenBSD 风格指南:

"Avoid using typedefs for structure types. This makes it impossible for applications to use pointers to such a structure opaquely, which is both possible and beneficial when using an ordinary struct tag." “避免对结构类型使用 typedef。这使得应用程序不可能不透明地使用指向这种结构的指针,这在使用普通结构标记时既可能又有益。”

From Linux kernel coding style:来自 Linux 内核编码风格:

"It's a mistake to use typedef for structures and pointers." “将 typedef 用于结构和指针是错误的。”

From Expert C Programming by Peter Van der Linden:来自 Peter Van der Linden 的 Expert C Programming:

"Don't bother with typedefs for structs. All they do is save you writing the word "struct", which is a clue that you probably shouldn't be hiding anyway." “不要为结构体的 typedef 烦恼。他们所做的只是让你不用写“结构体”这个词,这是一个你可能不应该隐藏的线索。”

It's more or less a matter of taste.这或多或少是品味问题。

By just declaring a struct tag, the name is also available to be used for variables, functions, or enumerators in the same scope (or even another type, if you enjoy confusion);通过声明一个struct标签,该名称也可用于同一范围内的变量、函数或枚举数(或者甚至是另一种类型,如果你喜欢混淆); and users must write the word struct , which makes their code more explicit.并且用户必须编写单词struct ,这使他们的代码更加明确。

By also declaring a type name, you allow people not to type struct if they don't want to.通过同时声明类型名称,您可以允许人们在他们不想时不要输入struct

My comment in the other question was referring to the declaration of a pointer type with the same name as the struct tag:我在另一个问题中的评论是指与结构标记同名的指针类型的声明:

typedef struct foo * foo;

Stylistically, this is slightly unpleasant because it hides the fact that it's a pointer.在风格上,这有点令人不快,因为它隐藏了它是一个指针的事实。 This hides the fact that it is a pointer;这隐藏了它是一个指针的事实; that is perhaps fine in the context of that question, where this is an opaque type defined by an API, but in my opinion would be rather rude for a non-opaque type.在该问题的上下文中,这可能没问题,这是由 API 定义的不透明类型,但在我看来,对于非不透明类型来说,这将是相当粗鲁的。 It also breaks compatibility with C++.它还破坏了与 C++ 的兼容性。 In that language, such a declaration is invalid, since struct foo introduces foo into the current namespace rather than a separate tag space, and prevents the declaration of any other type with the same name in that namespace.在该语言中,这样的声明是无效的,因为struct foofoo引入当前命名空间而不是单独的标记空间,并防止在该命名空间中声明任何其他具有相同名称的类型。

Just stick to a naming convention and you'll be fine.只要坚持命名约定,你就会没事的。

typedef struct
{
  //...
}              t_mytype;
//...
t_mytype thing;

This way you'll know it's a custom type.这样你就会知道它是一个自定义类型。 As for it being a struct, just use explicit names and not really t_mytype至于它是一个结构,只需使用显式名称而不是真正的t_mytype

One another argument against typedef is the difficulty it write clean headers.另一个反对 typedef 的论点是它编写干净的标头的难度。 Let's see an example of header:让我们看一个标题的例子:

#ifndef HEADER_H
#define HEADER_H
#include "s.h"
void f(struct s *);
#endif

This header can be improved.这个标题可以改进。 Indeed, struct s does not need to be defined.实际上, struct s不需要定义。 So it could be written:所以可以写成:

#ifndef HEADER_H
#define HEADER_H
struct s;
void f(struct s *);
#endif

Thus, the user may use struct s as an opaque struct and we can keep "sh" private.因此,用户可以使用struct s作为一个不透明的结构,我们可以保持"sh"私有。

Let's do the same thing but with typedef :让我们用typedef做同样的事情:

#ifndef HEADER_H
#define HEADER_H
typedef struct s s_t;
void f(s_t *);
#endif

The line typedef struct s s_t will appears in every header that want to use s_t * and I dislike redundant code.typedef struct s s_t将出现在每个想要使用s_t *标题中,我不喜欢冗余代码。 There are multiple ways to avoid that, but the easiest is probably to get rid of typedef.有多种方法可以避免这种情况,但最简单的方法可能是摆脱 typedef。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM