为什么“typedef struct foo foo;”被认为有害?
在C vs C ++中的typedef和struct命名空间中 ,其中一条注释似乎暗示暴露某些struct foo
比使用typedef更好…
typedef struct foo foo;
…然后在整个API中使用foo
而不是struct foo
。
后一种变体有任何缺点吗?
这取决于你喜欢单词struct
。 如果你觉得你的程序会通过自由的struct that
和struct tother
(当然你不能在C ++中使用struct
),那么一定要使用struct
版本。
就个人而言,我不认为重复struct
提供任何好处,我很乐意只使用typedef
名称。 并且因为C ++有效地提供了typedef struct xyz xyz;
自动声明(它不是很准确,尤其是因为你可以在C ++中明确地写出来,但是它足够接近你可能不必担心它),我认为使用它是完全合理的C. C编译器很满意,所以我通常使用typedef struct tag tag;
然后在需要的地方使用tag
和tag *
。
有关替代但完全可行的视图,请阅读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 foo
将foo
引入当前命名空间而不是单独的标记空间,并且阻止在该命名空间中声明具有相同名称的任何其他类型。
坚持命名惯例,你会没事的。
typedef struct { //... } t_mytype; //... t_mytype thing;
这样你就会知道它是一种自定义类型。 至于它是一个结构,只使用显式名称而不是真正的t_mytype