首页 > 解决方案 > 如果 struct 类型在另一个 .c 文件中定义,它会变成不完整类型吗?

问题描述

我对这段代码没有任何问题:

#include <stdio.h>
struct foo
{
  void * data;
};

int main()
{
  printf("%ul\n", sizeof(struct foo));
}

但是一旦结构在另一个文件中声明并提供给编译器,结构就会神奇地变成不完整的类型:

编辑(我没有提供所有代码):

: _

struct foo

公元前

#include "b.h"
struct foo
{
    void * data;
};

交流

#include <stdio.h>
#include "b.h"

int main()
{
    printf("%lu\n",sizeof(struct foo));
}

触发: $gcc a.c b.c

仍然是同样的错误:

error: invalid application of ‘sizeof’ to incomplete type ‘struct foo’
  printf("%lu\n",sizeof(struct foo));

标签: cstructsizeofincomplete-type

解决方案


一个翻译单元,即一个 .c文件及其#included.h文件必须是独立的,按要求的顺序包含编译翻译单元所需的所有定义声明。即使您.c在 GCC 命令行上提供了多个文件,这些文件中的每一个都被视为一个单独的翻译单元

顺序意味着翻译单元的 C 源代码可以一次性编译,意味着编译器可以在解析程序的同时生成机器代码,而不必在内存中保留超过绝对必要的内容,因此所有必要的声明和定义必须在需要之前出现在源代码中。

C11/C18 标准说( 6.5.3.4p1)

sizeof 运算符不应应用于具有函数类型或不完整类型的表达式[...]

(6.7.2.3p4)

  1. 具有相同范围并使用相同标记的结构、联合或枚举类型的所有声明都声明相同的类型。无论在同一翻译单元中是否有标记或该类型的其他声明,类型都是不完整的*[129]*,直到紧接在定义内容的列表的右大括号之后,然后才完成。

脚注129指出

[129]不完整类型只能在不需要该类型对象的大小时使用。例如,当typedef名称被声明为结构或联合的说明符时,或者当声明指向或返回结构或联合的函数时,不需要它。(参见 6.2.5 中的不完整类型。)在调用或定义这样的函数之前,规范必须是完整的。

即您的翻译单元a.c由以下代码组成:

// code included from <stdio.h>
...
// code included from "b.h"
struct foo;

// rest of code in a.c
int main()
{
    printf("%lu\n",sizeof(struct foo));
}

这是C编译器所拥有的所有知识,struct foo当它到达 6.7.2.3p4sizeof(struct foo)时,类型仍然完整并产生错误。struct foo

作为修复,b.h应该,而不是完全无用和无操作struct foo;具有实际的结构定义:

b.h

struct foo
{
    void * data;
};

推荐阅读