130

如果我有一个带有结构的 source.c 文件:

struct a { 
    int i;
    struct b {
        int j;
    }
};

这个结构如何在另一个文件(即func.c)中使用?

我应该创建一个新的头文件,在那里声明结构并将该头文件包含在其中func.c吗?

或者我应该在头文件中定义整个结构并将其包含在两者中source.cfunc.c?如何extern在两个文件中声明结构?

typedef应该吗?如果是这样,怎么做?

4

3 回答 3

153

如果这个结构要被其他文件func.c使用怎么办?

当文件(即func.c 文件)中使用类型时,它必须是可见的。最糟糕的方法是将其复制粘贴到每个需要它的源文件中。

正确的方法是将它放在头文件中,并在需要时包含此头文件。

我们是否应该打开一个新的头文件并在那里声明结构并将该头文件包含在 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 ;

就足够了,它减少了耦合。

或者我们可以在头文件中定义整个结构并将其包含在 source.c 和 func.c 中吗?

这是另一种方式,稍微简单一些,但模块化程度较低:一些只需要你的结构才能工作的代码仍然必须包含所有类型。

在 C++ 中,这可能会导致一些有趣的复杂情况,但是这超出了主题(没有 C++ 标签),所以我不会详细说明。

然后如何在两个文件中将该结构声明为 extern。?

也许我没有明白这一点,但是 Greg Hewgill 在他的帖子How to declare a structure in a header that is to be used by multiple files in c? 中有一个很好的答案?.

我们应该 typedef 它然后如何?

  • 如果您使用的是 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 ;

因此,您可以在任何想要避免添加 struct 关键字的地方使用 MyStruct,并且在 typedef 不起作用时仍然使用 MyStructTag(即前向声明)

编辑:

更正了关于 C99 结构声明的错误假设,正如Jonathan Leffler正确评论的那样。

编辑 2018-06-01:

Craig Barnes在他的评论中提醒我们,你不需要为结构“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 单独的“命名空间”来为结构和其他符号使用相同的名称,那么使用相同的名称会使阅读更简单.

于 2008-10-23T06:47:43.147 回答
38

对于要在多个源文件中使用的结构定义,您绝对应该将其放在头文件中。然后将该头文件包含在任何需要该结构的源文件中。

extern声明不用于结构定义,而是用于变量声明(即具有您已定义的结构类型的某些数据值)。如果要在多个源文件中使用相同的变量,请将其声明为extern头文件,如:

extern struct a myAValue;

然后,在一个源文件中,定义实际变量:

struct a myAValue;

如果您忘记这样做或不小心在两个源文件中定义了它,链接器会通知您。

于 2008-10-23T06:03:55.700 回答
7

啊:

#ifndef A_H
#define A_H

struct a { 
    int i;
    struct b {
        int j;
    }
};

#endif

好了,现在你只需要将 ah 包含到要使用此结构的文件中。

于 2008-10-23T06:01:55.907 回答