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

在C vs C ++中的typedef和struct命名空间中 ,其中一条注释似乎暗示暴露某些struct foo比使用typedef更好…

 typedef struct foo foo; 

…然后在整个API中使用foo而不是struct foo

后一种变体有任何缺点吗?

这取决于你喜欢单词struct 。 如果你觉得你的程序会通过自由的struct thatstruct tother (当然你不能在C ++中使用struct ),那么一定要使用struct版本。

就个人而言,我不认为重复struct提供任何好处,我很乐意只使用typedef名称。 并且因为C ++有效地提供了typedef struct xyz xyz; 自动声明(它不是很准确,尤其是因为你可以在C ++中明确地写出来,但是它足够接近你可能不必担心它),我认为使用它是完全合理的C. C编译器很满意,所以我通常使用typedef struct tag tag; 然后在需要的地方使用tagtag *


有关替代但完全可行的视图,请阅读Linux内核编码样式指南。


请注意,C2011允许您重新定义typedef ,只要它为同一类型别名:

ISO / IEC 9899:2011§6.7声明

语义

¶5声明指定一组标识符的解释和属性。 标识符的定义是该标识符的声明:

– 对于一个对象,导致为该对象保留存储;

– 用于function,包括function体; 119)

– 对于枚举常量,是标识符的(唯一)声明;

– 对于typedef名称,是标识符的第一个(或唯一)声明。

与C99相比,这是不可能的:

ISO / IEC 9899:1999§6.7声明

语义

¶5声明指定一组标识符的解释和属性。 标识符的定义是该标识符的声明:

– 对于一个对象,导致为该对象保留存储;

– 用于function,包括function体; 98)

– 对于枚举常量或typedef名称,是标识符的(唯一)声明。

只要您保持一致,这就简化了类型定义的创建(但只有在与您相关的每个平台上都有足够兼容的C2011编译器时)。

唯一的缺点(*)是它隐藏了foo是一个结构的事实,而不是一些内置类型的别名。

注意(*):这对你来说是不是一个缺点。

  • 它对完全不透明有好处(见下面的第一条评论)。
  • 要了解为什么有些人认为这是一个缺点,请检查linux内核编码风格 (typedefs章节)。

是否为typedef结构类型:

以下是一些意见(所有针对typedefing结构):

来自OpenBSD风格指南:

“避免对结构类型使用typedef。这使得应用程序不可能不透明地使用指向这种结构的指针,这在使用普通的struct标签时既可能又有益。”

从Linux内核编码风格:

“将typedef用于结构和指针是一个错误 。”

来自Peter Van der Linden的专家C编程:

“不要为typedef打扰结构。他们所做的只是保存你写”struct“这个词,这是你可能不应该隐藏的线索。”

这或多或少都是品味问题。

通过声明一个struct标签,该名称也可用于同一范围内的变量,函数或枚举器(如果您喜欢混淆,甚至可以用于另一种类型); 并且用户必须编写单词struct ,这使得他们的代码更加明确。

通过声明类型名称,您可以允许人们在不想要时键入struct

我在另一个问题中的评论是指一个与struct标签同名的指针类型的声明:

 typedef struct foo * foo; 

在风格上,这有点令人不愉快,因为它隐藏了它是指针的事实。 这隐藏了它是指针的事实; 在这个问题的上下文中,这可能很好,这是一个由API定义的opaque类型,但在我看来,对于非opaque类型来说,这是相当粗鲁的。 它还打破了与C ++的兼容性。 在该语言中,这样的声明是无效的,因为struct foofoo引入当前命名空间而不是单独的标记空间,并且阻止在该命名空间中声明具有相同名称的任何其他类型。

坚持命名惯例,你会没事的。

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

这样你就会知道它是一种自定义类型。 至于它是一个结构,只使用显式名称而不是真正的t_mytype