Answers:
在文件(即func.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 ++标记),因此我不再赘述。
我可能看不到这一点,但是Greg Hewgill在他的文章中给出了一个很好的答案:如何在标头中声明结构,以供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 struct MyStructTag
{
/* etc. */
} MyStruct ;
因此,您可以在要避免添加struct关键字的任何地方使用MyStruct,并且当typedef不起作用(即,正向声明)时仍可以使用MyStructTag。
乔纳森·莱夫勒(Jonathan Leffler)正确地指出了有关C99结构声明的错误假设。
克雷格·巴恩斯(Craig Barnes)在他的评论中提醒我们,您无需为结构“标记”名称及其“ typedef”名称保留单独的名称,就像我在上面为清楚起见所做的那样。
确实,上面的代码可以写成:
typedef struct MyStruct
{
/* etc. */
} MyStruct ;
IIRC,实际上这是C ++在后台使用其更简单的struct声明来使其与C兼容的方式:
// C++ explicit declaration by the user
struct MyStruct
{
/* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;
回到C,我已经看到了两种用法(分别使用名称和相同名称),并且我都没有缺点,因此如果您不对结构和其他符号使用C单独的“命名空间”,则使用相同的名称会使阅读更加容易。
struct
标记和名称无需使用其他名称typedef
。C为struct
标签使用了不同的名称空间,因此您可以同时使用MyStruct
它们。
对于要在多个源文件中使用的结构定义,您绝对应该将其放在头文件中。然后将该头文件包含在任何需要该结构的源文件中。
该extern
声明不用于结构定义,而是用于变量声明(即,某些具有您定义的结构类型的数据值)。如果要在多个源文件中使用同一变量,请extern
在头文件中将其声明为:
extern struct a myAValue;
然后,在一个源文件中,定义实际变量:
struct a myAValue;
如果您忘记这样做或在两个源文件中意外定义了它,则链接器将让您知道这一点。
GLOBAL
as extern
或不定义,然后将变量声明为GLOBAL struct a myAValue;
。从大多数源文件中,您可以安排要使用的#define GLOBAL extern
版本(声明变量),而从一个源文件中恰好会导致使用空的定义,因此可以定义变量。
struct b
,但随后您的结构a
声明一个未使用的类型(您可能应k
在内部大括号和后定义一个成员名,–在分号之前