简体   繁体   English

什么时候使用没有 typedef 的结构体有意义?

[英]When does it make sense to use a struct without a typedef?

Structs in C declare a data structure that associates different data types into a contiguous piece of memory. C 中的结构声明了一个数据结构,它将不同的数据类型关联到一块连续的内存中。

Typedefs are a way to create user-defined data type names. Typedef 是一种创建用户定义的数据类型名称的方法。 This is useful for many applications including <stdint.h>这对许多应用程序很有用,包括<stdint.h>

Structs seem to be exclusively used with typedefs.结构似乎专门与 typedef 一起使用。 It seems like the default behaviour of defining a struct should also define a typedef .似乎定义struct的默认行为也应该定义typedef

Why would I ever want to define struct without also using a typedef ?为什么我想在不使用typedef情况下定义struct

It's a matter of personal preference, possibly imposed onto other people working on the same project as a convention.这是个人偏好的问题,可能会强加给从事同一项目的其他人作为惯例。 For instance, the Linux kernel coding style guide discourages the introduction of new typedefs in no uncertain terms.例如,Linux 内核编码风格指南明确不鼓励引入新的 typedef

Though I don't necessarily agree with everything in that guide, some of which seems silly (for instance vps_t a; example could be virtual_container_t a; : the issue hinges on the cryptic name that is chosen for typedef more than the existence of the typedef), in my TXR language project, here are some raw stats:虽然我不一定同意该指南中的所有内容,但其中一些似乎很愚蠢(例如vps_t a;示例可能是virtual_container_t a; :问题取决于为typedef选择的神秘名称,而不是typedef的存在),在我的 TXR 语言项目中,这里有一些原始统计数据:

txr$ git grep '^typedef struct' '*/*.[ch]' '*.[ch]' | wc
     25      91     839
txr$ git grep '^struct' '*/*.[ch]' '*.[ch]' | wc
    135     528    4710

Lines of code beginning with struct outnumber typedef struct lines by a factor of 5.4!struct开头的代码行比typedef struct行多 5.4 倍!

The union/tag namespace feature of C means that you can have a variable called foo in the same scope as a struct foo without a clash, which is useful. C 的 union/tag 命名空间特性意味着您可以在与struct foo相同的范围内拥有一个名为foo的变量而不会发生冲突,这很有用。 This extra namespace gives us an opportunity not to pollute the regular identifier namespace with user-defined type names, which improves hygiene.这个额外的命名空间让我们有机会不使用用户定义的类型名称污染常规标识符命名空间,从而提高卫生。

The cost is that we have to type struct foo instead of just foo in declarations.代价是我们必须在声明中输入struct foo而不仅仅是foo

It makes particular sense if you have experience with languages in which class/type names do not intrude into the lexical variable namespace, like Common Lisp.如果您有使用类/类型名称不会侵入词法变量命名空间的语言(如 Common Lisp)的经验,这将特别有意义。

The above code base, though, compiles as C++, so that throws a bit of a monkey wrench into it.但是,上面的代码库编译为 C++,所以这会给它带来一些麻烦。 In C++, struct foo defines foo as a type, which can be referenced in the ordinary namespace.在C ++中, struct foo定义foo作为一种类型的,它可以在普通命名空间引用。

Another reason is that there is some clarity.另一个原因是有一些清晰度。 When we see a declaration like:当我们看到这样的声明时:

struct foo x;

we know that x is a structure, whereas我们知道 x 是一个结构,而

foo x;

could be anything;可以是任何东西; it could be typedef double foo .它可能是typedef double foo Sometimes we go for that kind of abstraction.有时我们会追求那种抽象。 When you want to hide how something is implemented, reach for typedef .当您想隐藏某些内容的实现方式时,请使用typedef However, typedef doesn't provide perfect abstraction.但是, typedef没有提供完美的抽象。

Also, if we see:另外,如果我们看到:

struct foo f;
struct bar b;

we know that these are necessarily different, incompatible types.我们知道这些必然是不同的、不兼容的类型。 We do not know that given:我们不知道给出:

foo f;
bar b;

They could both be typedef s for the same structure or for int for all we know.它们都可以是相同结构的typedef也可以是我们所知道的int

If you typedef pointer types, but the code dereferences them, it looks pretty silly:如果你typedef指针类型,但代码取消引用它们,它看起来很傻:

foo x = get_foo();
char *fname = x->name; /* what? */

That kernel coding style document has this to say about the above: In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.该内核编码风格文档对上述内容有这样的说法:通常,具有可以合理直接访问的元素的指针或结构永远不应该是 typedef。

Not using typedef for structures has as much to do with some of the hygiene of using the tag namespace, as it has to do with avoiding typedef as such: keeping the code explicit, and reserving typedef for situations in which we actually need a proper abstraction.不为结构使用typedef与使用标签命名空间的一些卫生有关,因为它与避免typedef :保持代码显式,并为我们实际上需要适当抽象的情况保留typedef .

Structs seem to be exclusively used with typedefs.结构似乎专门与 typedef 一起使用。

This is a mistaken impression.这是一种错误的印象。 Structs are frequently used without typedefs, and I personally prefer that.结构经常在没有 typedef 的情况下使用,我个人更喜欢这样。 There are numerous struct types declared and used, without built-in typedefs, by the C standard library and POSIX standard library extension functions, for example.例如,C 标准库和 POSIX 标准库扩展函数声明和使用了许多没有内置 typedef 的结构类型。

It seems like the default behavior of defining a struct should also define a typedef.似乎定义结构的默认行为也应该定义 typedef。

In C++, it effectively does.在 C++ 中,它有效地做到了。

Why would I ever want to define struct without also using a typedef?为什么我想在不使用 typedef 的情况下定义结构?

Why would you ever want to define a struct with a typedef ?为什么要使用typedef定义struct Using a (tagged) structure type via the struct keyword and its tag clarifies what kind of type it is, and enables you to determine quickly by eye whether two types are the same.通过struct关键字及其标记使用(标记的)结构类型可以阐明它是哪种类型,并使您能够通过肉眼快速确定两种类型是否相同。 On the other hand, a typedef ed alias can represent any type at all, and there can be multiple such aliases for the same type.另一方面,一个typedef ed 别名可以代表任何类型,并且同一类型可以有多个这样的别名。

There are some good and appropriate uses of typedef , but there are a lot of other uses whose propriety is a code style consideration. typedef有一些好的和适当的用途,但还有许多其他用途,其适当性是代码风格的考虑。 Myself, I strongly prefer styles that minimize use of typedef .我自己,我非常喜欢尽量减少使用typedef样式。

typedef is just a convenience to allow you to refer to your struct without explicitly stating struct MyStruct every time you refer to it. typedef只是一种方便,它允许您在每次引用结构时无需显式声明struct MyStruct引用它。
Some actually prefer this explicitness, making it clear you're working with a user-defined type.有些人实际上更喜欢这种明确性,这清楚地表明您正在使用用户定义的类型。

我从来没有对我的结构进行 typedef,这样它们就可以更容易地在其他头文件中声明为“extern”。

You ask: Why would I ever want to define struct without also using a typedef?你问:为什么我要在不使用 typedef 的情况下定义结构?

It depends what you mean by 'define a struct'.这取决于您所说的“定义结构”是什么意思。 Not all uses of struct are to define named types.并非 struct 的所有用途都是定义命名类型。

For example you could define a variable via例如,您可以通过定义一个变量

struct  
{   double  a, b;
}   dbls = { -1.0, 1.0};

Then dbls.a etc makes sense, but there is no named type.然后 dbls.a 等是有道理的,但没有命名类型。

Similarly in an anonymous union you might have同样,在匿名工会中,您可能有

struct  ructT
{   union
    {   struct { int a; int b; } ints;
        struct { float a; float b; } floats;
    };
};

Here one has defined a type struct ructT but the inner structs are unnamed.这里定义了一个类型 struct ructT 但内部结构是未命名的。

In each of these cases if one was to insist on typedefs, there would be more names to dream up, and more code to type.在这些情况中的每一种情况下,如果要坚持使用 typedef,就会有更多的名字可以想出来,还有更多的代码要输入。

typedef isn't just about saving a few keystrokes - it's about abstracting away implementation details of the underlying type. typedef不仅仅是为了节省一些按键——它是为了抽象出底层类型的实现细节。 IOW, if you provide a typedef name for a struct type, you should also provide a complete API for setting and accessing members, formatting for output, allocating, deallocating, etc. You're hiding the "struct"-ness of the type from whomever is using it. IOW,如果您为struct类型提供 typedef 名称,您应该提供一个完整的 API 来设置和访问成员、格式化输出、分配、解除分配等。您正在隐藏类型的“结构”-ness谁在使用它。 Think about the FILE type in the standard library - that's a typedef name, usually for some implementation-specific structure.想想标准库中的FILE类型——这是一个 typedef 名称,通常用于某些特定于实现的结构。 However, you never access any element of a FILE type directly - you just pass FILE * objects to various functions ( fprintf , fread , feof , ferror , etc.) that hide the implementation from you.但是,您永远不会直接访问FILE类型的任何元素 - 您只需将FILE *对象传递给各种隐藏实现的函数( fprintffreadfeofferror等)。

If you're expecting the user of the type to explicitly access members with the .如果您希望该类型的用户显式访问带有. or -> operators, then don't create a typedef name for it - just leave it as struct whatever .->运算符,然后不要为其创建 typedef 名称 - 只需将其保留为struct whatever Otherwise you create a "leaky" abstraction, which creates heartburn down the line.否则,您会创建一个“泄漏”的抽象,这会导致胃灼热。

Similar rule for pointer types - don't hide the "pointer"-ness of a type behind a typedef unless you're willing to create a full API to abstract away pointer operations as well.指针类型的类似规则 - 不要在typedef后面隐藏类型的“指针”,除非您愿意创建一个完整的 API 来抽象指针操作。

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

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