如果我有一个具有 struct 的 source.c 文件:
struct a { int i; struct b { int j; } };
如何在另一个文件(即 func.c)中使用这个结构?
func.c
我是否应该创建一个新的头文件,在那里声明结构,并在 func.c中包含该头文件?
还是应该在头文件中定义整个结构,并在 source.c和 func.c中包含它?如何在两个文件中声明结构 extern?
source.c
extern
我应该 typedef它吗? 如果是,如何?
typedef
啊哈:
#ifndef A_H #define A_H struct a { int i; struct b { int j; } }; #endif
好了,现在你只需要把 a.h 包含到你想要使用这个结构的文件中。
对于跨多个源文件使用的结构定义,您一定要将其放在一个头文件中。然后将该头文件包含在需要该结构的任何源文件中。
extern声明不用于结构定义,而是用于变量声明(即定义了结构类型的一些数据值)。如果希望在多个源文件中使用相同的变量,请在头文件中将其声明为 extern,如下所示:
extern struct a myAValue;
然后,在 一源文件中定义实际的变量:
struct a myAValue;
如果您忘记这样做,或者不小心在两个源文件中定义了它,链接器会让您知道这一点。
当一个类型在一个文件中使用时(比如 fun.c 文件) ,它必须是可见的。最糟糕的方法是复制粘贴到每个源文件需要它。
正确的方法是将它放在一个头文件中,并在需要时包含这个头文件。
这是我更喜欢的解决方案,因为它使代码高度模块化:
#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME #define SOME_HEADER_GUARD_WITH_UNIQUE_NAME struct a { int i; struct b { int j; } }; #endif
我会把使用这个结构的函数放在同一个标题中(这个函数是它的“接口”的“语义”部分)。
通常,我可以用结构名称命名文件,然后再次使用该名称来选择头保护定义。
如果需要使用指向结构的指针声明函数,则不需要完整的结构定义。简单的前向声明如下:
struct a ;
就足够了,而且它减少了耦合。
这是另一种方法,稍微容易一些,但是模块化程度较低: 一些只需要结构就可以工作的代码仍然必须包含所有类型。
在 C + + 中,这可能会导致有趣的复杂性,但是这与主题无关(没有 C + + 标记) ,因此我不会详细说明。
也许我不明白这一点,但是格雷格 · 休吉尔在他的文章 如何在一个头中声明一个结构,以供 c 中的多个文件使用?中给出了一个很好的答案。
原因是 C 结构管理可能很麻烦: 必须在所有使用的地方声明 struct 关键字:
struct MyStruct ; /* Forward declaration */ struct MyStruct { /* etc. */ } ; void doSomething(struct MyStruct * p) /* parameter */ { struct MyStruct a ; /* variable */ /* etc */ }
而 typedef 将使您能够在不使用 struct 关键字的情况下编写它。
struct MyStructTag ; /* Forward declaration */ typedef struct MyStructTag { /* etc. */ } MyStruct ; void doSomething(MyStruct * p) /* parameter */ { MyStruct a ; /* variable */ /* etc */ }
这是 很重要,你仍然保留一个结构的名称。写:
typedef struct { /* etc. */ } MyStruct ;
将只创建一个具有 typedef 名称的匿名结构,并且您将无法转发-声明它。因此,请遵循以下格式:
typedef struct MyStructTag { /* etc. */ } MyStruct ;
因此,您可以在任何地方使用 MyStruct,以避免添加 struct 关键字,并且在 typedef 不能工作时仍然使用 MystructTag (即前向声明)
纠正了关于 C99结构声明的错误假设,乔纳森 · 莱弗勒正确地指出了这一点。
Craig Barnes 在他的注释中提醒我们,您不需要为 struct“ tag”名称和它的“ typedef”名称保留单独的名称,就像我上面为了清晰起见所做的那样。
事实上,上面的代码可以写成:
typedef struct MyStruct { /* etc. */ } MyStruct ;
IIRC,这实际上是 C + + 在幕后用它更简单的结构声明所做的,以保持它与 C 的兼容性:
// C++ explicit declaration by the user struct MyStruct { /* etc. */ } ; // C++ standard then implicitly adds the following line typedef MyStruct MyStruct;
回到 C 语言,我已经看到了两种用法(不同的名称和相同的名称) ,没有一种有我知道的缺点,所以如果不使用 C 为结构和其他符号分隔“名称空间”,使用相同的名称会使阅读更简单。