如果在另一个 .c 文件中定义了 struct 类型,它就变成了不完整的类型?
If struct type is defined in another .c file, it becomes incomplete type?
这段代码我没问题:
#include <stdio.h>
struct foo
{
void * data;
};
int main()
{
printf("%ul\n", sizeof(struct foo));
}
但是一旦结构在另一个文件中声明并提供给编译器,结构就会神奇地变成不完整类型:
编辑(我没有提供所有代码):
b.h:
struct foo
b.c:
#include "b.h"
struct foo
{
void * data;
};
a.c:
#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));
编译器不使用多个源文件。每个源文件都独立编译成目标文件。在编译阶段,a.c
和 b.c
彼此未知。所以 a.c
无法编译成对象,因为它取决于对 struct foo
是什么的了解。
这是头文件的用武之地。它可用于定义将由不同源文件共享的公共对象,然后您将该头文件包含在需要使用它的每个源文件中.
If struct type is defined in another .c file, it becomes incomplete
type?
如果在需要其定义的当前翻译单元中看不到它的定义,它就成为不完整的类型,例如在运算符 sizeof
.
中使用它
在包含此代码的翻译单元中
#include <stdio.h>
int main()
{
printf("%lu\n",sizeof(struct foo));
}
struct foo
未定义。
所以编译器自然会报错,说使用了不完整的类型。
如果使用多个翻译单元,您应该将结构定义放在 header 中。
或者,如果您只需要知道结构的大小并且它没有在其他任何地方使用,那么您可以只写
#include <stdio.h>
int main()
{
printf("%zu\n",sizeof(struct foo { void * data; } ));
}
请注意,在上面的程序中,类型 struct foo
在 main 的块范围内定义。
编辑: 更新您的问题后,然后在此翻译单元中
#include <stdio.h>
#include "b.h"
int main()
{
printf("%lu\n",sizeof(struct foo));
}
您在 header b.h
中的结构声明不完整(您忘记在声明后放置分号)
struct foo;
^^^
所以实际上与之前的演示程序相比,除了结构声明现在具有文件范围而不是块范围之外,与之前的演示程序相比没有任何变化,因为它发生在之前的程序中。编译器无法确定没有定义的结构的大小
注意这个命令中的那个
$gcc a.c b.c
文件a.c
和b.c
是分开编译的。
一个翻译单元,即一个.c
文件及其#include
d.h
文件必须 self-standing,按要求的顺序包含编译翻译单元所需的所有 定义 和 声明 。即使您在 GCC 命令行上提供了几个 .c
文件,这些文件中的 每个 都被视为一个 单独的 翻译单元 .
in order表示翻译单元的C源代码可以single pass编译,也就是说编译器可以在解析程序的同时生成机器代码,绝不会在绝对必要的情况下保留在内存中,因此所有必要的声明和定义必须出现在源代码中 before 它们是需要的.
C11/C18 标准说 (6.5.3.4p1) 那
The sizeof operator shall not be applied to an expression that has function type or an incomplete type [...]
- All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type. Irrespective of whether there is a tag or what other declarations of the type are in the same translation unit, the type is incomplete*[129]* until immediately after the closing brace of the list defining the content, and complete thereafter.
用脚注 129 说明
[129] An incomplete type may only by used when the size of an object of that type is not needed. It is not needed, for example, when a typedef
name is declared to be a specifier for a structure or union, or when a pointer to or a function returning a structure or union is being declared. (See incomplete types in 6.2.5.) The specification has to be complete before such a function is called or defined.
即你的翻译单元 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
的所有了解,当它达到 sizeof(struct foo)
时, 6.7.2.3p4类型struct foo
仍然不完整,产生错误。
作为修复,b.h
应该而不是 完全没用,no-op struct foo;
具有实际的结构定义:
b.h
:
struct foo
{
void * data;
};
与$gcc a.c b.c
一起编译时,a.c
和b.c
仍然是分开编译的。此后,链接器将生成机器代码的目标文件抓在一起。
当你使用
printf("%lu\n",sizeof(struct foo));
sizeof
只能应用于完整类型,因为 sizeof
需要知道类型的确切大小才能获得该类型对象的字节大小。
但这还没有实现,因为 struct foo
只是 forward-declared 在包含的 b.h
文件中。
struct foo
的 forward-declaration 是允许的,但 struct foo
是一个不完整的类型,只要它没有被真正声明。这尤其与单独的 TLU 有关。
b.c
中 struct foo
的声明使 struct foo
成为一个完整的类型,在应用 sizeof
运算符时在 a.c
中不可见;因此错误。
可能的解决方案:
将struct foo
的forward-declaration替换为b.h
内的struct foo
的声明,并省略´struct foo
的声明在 b.c
.
#include "b.c"
in a.c
在调用 printf()
.
时应用 sizeof
运算符之前
只需在a.c
中声明struct foo
。 :-)
这段代码我没问题:
#include <stdio.h>
struct foo
{
void * data;
};
int main()
{
printf("%ul\n", sizeof(struct foo));
}
但是一旦结构在另一个文件中声明并提供给编译器,结构就会神奇地变成不完整类型:
编辑(我没有提供所有代码):
b.h:
struct foo
b.c:
#include "b.h"
struct foo
{
void * data;
};
a.c:
#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));
编译器不使用多个源文件。每个源文件都独立编译成目标文件。在编译阶段,a.c
和 b.c
彼此未知。所以 a.c
无法编译成对象,因为它取决于对 struct foo
是什么的了解。
这是头文件的用武之地。它可用于定义将由不同源文件共享的公共对象,然后您将该头文件包含在需要使用它的每个源文件中.
If struct type is defined in another .c file, it becomes incomplete type?
如果在需要其定义的当前翻译单元中看不到它的定义,它就成为不完整的类型,例如在运算符 sizeof
.
在包含此代码的翻译单元中
#include <stdio.h>
int main()
{
printf("%lu\n",sizeof(struct foo));
}
struct foo
未定义。
所以编译器自然会报错,说使用了不完整的类型。
如果使用多个翻译单元,您应该将结构定义放在 header 中。
或者,如果您只需要知道结构的大小并且它没有在其他任何地方使用,那么您可以只写
#include <stdio.h>
int main()
{
printf("%zu\n",sizeof(struct foo { void * data; } ));
}
请注意,在上面的程序中,类型 struct foo
在 main 的块范围内定义。
编辑: 更新您的问题后,然后在此翻译单元中
#include <stdio.h>
#include "b.h"
int main()
{
printf("%lu\n",sizeof(struct foo));
}
您在 header b.h
中的结构声明不完整(您忘记在声明后放置分号)
struct foo;
^^^
所以实际上与之前的演示程序相比,除了结构声明现在具有文件范围而不是块范围之外,与之前的演示程序相比没有任何变化,因为它发生在之前的程序中。编译器无法确定没有定义的结构的大小
注意这个命令中的那个
$gcc a.c b.c
文件a.c
和b.c
是分开编译的。
一个翻译单元,即一个.c
文件及其#include
d.h
文件必须 self-standing,按要求的顺序包含编译翻译单元所需的所有 定义 和 声明 。即使您在 GCC 命令行上提供了几个 .c
文件,这些文件中的 每个 都被视为一个 单独的 翻译单元 .
in order表示翻译单元的C源代码可以single pass编译,也就是说编译器可以在解析程序的同时生成机器代码,绝不会在绝对必要的情况下保留在内存中,因此所有必要的声明和定义必须出现在源代码中 before 它们是需要的.
C11/C18 标准说 (6.5.3.4p1) 那
The sizeof operator shall not be applied to an expression that has function type or an incomplete type [...]
- All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type. Irrespective of whether there is a tag or what other declarations of the type are in the same translation unit, the type is incomplete*[129]* until immediately after the closing brace of the list defining the content, and complete thereafter.
用脚注 129 说明
[129] An incomplete type may only by used when the size of an object of that type is not needed. It is not needed, for example, when a
typedef
name is declared to be a specifier for a structure or union, or when a pointer to or a function returning a structure or union is being declared. (See incomplete types in 6.2.5.) The specification has to be complete before such a function is called or defined.
即你的翻译单元 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
的所有了解,当它达到 sizeof(struct foo)
时, 6.7.2.3p4类型struct foo
仍然不完整,产生错误。
作为修复,b.h
应该而不是 完全没用,no-op struct foo;
具有实际的结构定义:
b.h
:
struct foo
{
void * data;
};
与$gcc a.c b.c
一起编译时,a.c
和b.c
仍然是分开编译的。此后,链接器将生成机器代码的目标文件抓在一起。
当你使用
printf("%lu\n",sizeof(struct foo));
sizeof
只能应用于完整类型,因为 sizeof
需要知道类型的确切大小才能获得该类型对象的字节大小。
但这还没有实现,因为 struct foo
只是 forward-declared 在包含的 b.h
文件中。
struct foo
的 forward-declaration 是允许的,但 struct foo
是一个不完整的类型,只要它没有被真正声明。这尤其与单独的 TLU 有关。
b.c
中 struct foo
的声明使 struct foo
成为一个完整的类型,在应用 sizeof
运算符时在 a.c
中不可见;因此错误。
可能的解决方案:
将
struct foo
的forward-declaration替换为b.h
内的struct foo
的声明,并省略´struct foo
的声明在b.c
.
时应用#include "b.c"
ina.c
在调用printf()
.sizeof
运算符之前只需在
a.c
中声明struct foo
。 :-)