[英]Pure C: when using typdef void StructName in header file, the header file can't be included into the .c file
I have a header file that looks like this:我有一个看起来像这样的 header 文件:
typedef void Square;
extern Square* Square_Init (int width, int height);
extern void Square_Delete (Cube* cube);
extern int Square_GetWidth (Cube* cube);
extern int Square_GetHeight (Cube* cube);
and a.c file, looking something like this:和 a.c 文件,看起来像这样:
/* #include "square.h" */ /* compiler gets mad for redefining Square */
typedef struct {
unsigned int width;
unsigned int height;
} Square;
Square* Square_Init (int width, int height) {. . .}
void Square_Delete (Cube* cube) {. . .}
int Square_GetWidth (Cube* cube) {. . .}
int Square_GetHeight (Cube* cube) {. . .}
When I finally include my header file in let's say main.c, all the functions work well.当我最终将我的 header 文件包含在 main.c 中时,所有功能都运行良好。 It is just a bit odd for me, that I can't include the square.h file into the square.c file.
对我来说有点奇怪,我不能将 square.h 文件包含到 square.c 文件中。 Can it be done somehow?
可以以某种方式完成吗?
What you seem to want to do is an opaque type.您似乎想要做的是不透明的类型。 But
void *
is not a type compatible with struct pointers, so you cannot use them interchangeably, and most definitely cannot use void
interchangeably with a structure type.但是
void *
不是与结构指针兼容的类型,因此您不能互换使用它们,并且绝对不能将void
与结构类型互换使用。
The correct way is to use a tagged structure without definition in the header, for example:正确的做法是使用header中没有定义的标记结构,例如:
typedef struct square Square;
and if you include the header in your .c
file, you just need to add:如果您在
.c
文件中包含 header ,则只需添加:
struct square {
unsigned int width;
unsigned int height;
};
This code...这段代码...
typedef void Square;
... is ok in itself. ... 本身没问题。 It declares the identifier
Square
to be an alias for the type void
.它将标识符
Square
声明为void
类型的别名。
This code...这段代码...
typedef struct { unsigned int width; unsigned int height; } Square;
... is also ok by itself. ...本身也可以。 It declares the identifier
Square
to be an alias for a tagless structure type with members { unsigned int width; unsigned int height; }
它将标识符
Square
声明为具有成员{ unsigned int width; unsigned int height; }
的无标记结构类型的别名。 { unsigned int width; unsigned int height; }
{ unsigned int width; unsigned int height; }
. { unsigned int width; unsigned int height; }
。
But the two are not at all compatible with each other.但两者完全不兼容。 Therefore, if you include the header into a C source file that includes the latter typedef then you have two conflicting declarations of the same
typedef
identifier.因此,如果您将 header 包含到包含后者 typedef 的 C 源文件中,那么您有两个相同
typedef
标识符的冲突声明。 Not only is the resulting behavior undefined, but this is one of the cases that a conforming C compiler is required to diagnose.不仅结果行为未定义,而且这是需要符合标准的 C 编译器进行诊断的情况之一。
Furthermore, although this declaration...此外,虽然这个声明...
extern Square* Square_Init (int width, int height);
... is valid with either typedef
, it has slightly different meaning depending on which is in scope where it appears. ... 对任何一个
typedef
都有效,它的含义略有不同,具体取决于它出现在 scope 中的哪个位置。 As a result, code that calls the function with the declaration from the header in scope has undefined behavior (but this is not a case that the compiler is required to diagnose).因此,使用 scope 中 header 的声明调用 function 的代码具有未定义的行为(但这不是编译器需要诊断的情况)。
Do not be confused by the fact that C provides automatic conversions back and forth between void *
and other object pointer types.不要被 C 提供
void *
和其他 object 指针类型之间的自动来回转换这一事实混淆。 That's a matter of values being somewhat interchangeable, but it does not mean that the types are interchangeable.这是值可以互换的问题,但这并不意味着类型可以互换。
Nevertheless, inasmuch as it is common in modern C implementations for pointers to different kinds of objects all to have the same size and representation, it is not so surprising that the undefined behavior arising from calling the function with a mismatched declaration in scope happens to manifest (so far) as exactly the behavior you expected. Nevertheless, inasmuch as it is common in modern C implementations for pointers to different kinds of objects all to have the same size and representation, it is not so surprising that the undefined behavior arising from calling the function with a mismatched declaration in scope happens to manifest (到目前为止)完全符合您的预期。 But that doesn't mean you should do this.
但这并不意味着你应该这样做。
The easiest thing to do would be to move the latter typedef
to the header, so that everyone agrees completely about what a Square
is.最简单的做法是将后一个
typedef
移动到 header,这样每个人都完全同意Square
是什么。 However, if you want to hide the definition of Square
while allowing other code to use pointers to instances of that type and maintaining substantial type safety, then the header can forward declare Square
as a structure type without (ever) defining the members, as Antti demonstrates in his answer .但是,如果您想隐藏
Square
的定义,同时允许其他代码使用指向该类型实例的指针并保持实质性的类型安全,那么 header 可以将Square
转发声明为结构类型,而无需(永远)定义成员,如 Antti在他的回答中表明。 This makes Square
an "opaque type" from the perspective of code that has only the declaration from the header.从只有 header 声明的代码的角度来看,这使得
Square
成为“不透明类型”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.