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

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

C 中的结构声明一个数据结构,将不同的数据类型关联到一块连续的内存中。

Typedef 是一种创建用户定义的数据类型名称的方法。这对许多应用程序都很有用,包括 <stdint.h>

结构似乎专门与 typedef 一起使用。似乎定义 struct 的默认行为也应该定义 typedef.

为什么我要在不使用 typedef 的情况下定义 struct

typedef 只是一种方便,允许您在每次引用结构时无需明确声明 struct MyStruct
有些人实际上更喜欢这种明确性,清楚地表明您正在使用用户定义的类型。

这是个人喜好问题,可能会强加给从事同一项目的其他人作为惯例。例如,Linux 内核编码风格指南 discourages the introduction of new typedefs 毫不含糊。

虽然我不一定同意该指南中的所有内容,但其中一些看起来很愚蠢(例如 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

struct 开头的代码行数超过 typedef struct 行 5.4 倍!

C 的 union/tag 命名空间特性意味着您可以在与 struct foo 相同的范围内拥有一个名为 foo 的变量而不会发生冲突,这很有用。这个额外的命名空间使我们有机会不使用用户定义的类型名称污染常规标识符命名空间,从而提高卫生水平。

代价是我们必须在声明中键入 struct foo,而不仅仅是 foo

如果您使用过 class/type 名称不会侵入词法变量名称空间的语言(如 Common Lisp),这就特别有意义。

不过,上面的代码库编译为 C++,因此会有些麻烦。在C++中,struct foofoo定义为一个类型,可以在普通命名空间中引用。

另一个原因是有一些清晰度。当我们看到这样的声明时:

struct foo x;

我们知道 x 是一个结构,而

foo x;

可以是任何东西;可能是 typedef double foo。有时我们会追求那种抽象。如果您想隐藏某些内容的实现方式,请使用 typedef。然而,typedef 并没有提供完美的抽象。

此外,如果我们看到:

struct foo f;
struct bar b;

我们知道这些必然是不同的、不兼容的类型。我们不知道给定:

foo f;
bar b;

对于相同的结构,它们可能都是 typedef,或者据我们所知,它们都是 int

如果你 typedef 指针类型,但代码取消引用它们,它看起来很傻:

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

该内核编码风格文档对上述内容有如下说法:一般来说,指针或具有可以合理直接访问的元素的结构永远不应该是 typedef。

不对结构使用 typedef 与使用标记命名空间的某些卫生习惯有很大关系,因为它与避免 typedef 一样:保持代码明确,并为我们实际需要适当抽象的情况保留 typedef

Structs seem to be exclusively used with typedefs.

这是一个错误的印象。经常在没有 typedef 的情况下使用结构,我个人更喜欢这样。例如,C 标准库和 POSIX 标准库扩展函数声明和使用了许多没有内置类型定义的结构类型。

It seems like the default behavior of defining a struct should also define a typedef.

在 C++ 中,它确实有效。

Why would I ever want to define struct without also using a typedef?

您为什么要定义一个 struct 一个 typedef?通过 struct 关键字及其标记使用(标记的)结构类型可以阐明它是哪种类型,并使您能够通过肉眼快速确定两种类型是否相同。另一方面,一个 typedefed 别名可以代表任何类型,并且同一类型可以有多个这样的别名。

typedef 有一些好的和适当的用途,但还有许多其他用途的适当性是代码风格的考虑。我个人非常喜欢尽量减少使用 typedef.

的样式

我从来没有对我的结构进行类型定义,这样它们就可以更容易地在其他 headers 中声明为“外部”。

你问:为什么我要定义结构而不使用 typedef?

这取决于你所说的 'define a struct' 是什么意思。并非所有 struct 的用途都是定义命名类型。

例如,您可以通过

定义一个变量
struct  
{   double  a, b;
}   dbls = { -1.0, 1.0};

然后dbls.a等是有道理的,但是没有命名类型。

类似地,在匿名工会中,您可能有

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

这里定义了一个类型 struct ructT 但内部结构未命名。

在上述每一种情况下,如果坚持使用 typedef,就会有更多的名称需要想出,也有更多的代码需要输入。

typedef 不仅仅是为了节省几次击键——它是关于抽象出底层类型的实现细节。 IOW,如果您为 struct 类型提供 typedef 名称,您应该 提供完整的 API 用于设置以及访问成员、格式化输出、分配、解除分配等。您正在向使用它的任何人隐藏类型的“结构”。想想标准库中的 FILE 类型——这是一个 typedef 名称,通常用于某些特定于实现的结构。但是,您永远不会直接访问 FILE 类型的任何元素 - 您只需将 FILE * 对象传递给各种函数(fprintffreadfeofferror, 等等) 对你隐藏了实现。

如果您希望该类型的用户使用 .-> 运算符显式访问成员,那么 不要 为它创建一个 typedef 名称 - 只需将其保留为 struct <em>whatever</em>。否则你会创建一个“有漏洞的”抽象,这会导致胃灼热。

指针类型的类似规则 - 不要在 typedef 后面隐藏类型的“指针”特性,除非您愿意创建一个完整的 API 来抽象指针操作还有。