当两个文件相互包含时,为什么我不能有一个内部结构?
Why can't I have an inner structure when two files include each other?
对于上下文,我正在编写一个操作系统:
我有一个 struct vt_device_s
和一个 struct __vt_device_s
,它们是特定于体系结构的,位于 vt_device_s
内部,如下所示:
struct
vt_device_s
{
struct __vt_device_s __device;
size_t cursor_x;
size_t cursor_y;
};
现在是架构结构:
struct
__vt_device_s
{
uint16_t *memory;
size_t memory_len;
};
header <dev/vt.h>
知道 <sys/_vt.h>
中定义的 __vt_device_s
因为它包含在内,但我得到这个错误:
error: field '__device' has incomplete type
48 | struct __vt_device_s __device;
|
我意识到这是因为两个文件相互依赖(整个冲突是由 _vt.c
including _vt.h
including vt.h
including _vt.h
引起的)但我不知道怎么理解是编译问题。我在两个文件中都包含了守卫!
PS:我知道如果我使用指针,这将是一个 non-issue,但由于它是一个操作系统,这个 driver 需要在设置分页之前运行(即是,malloc
和 free
还不存在)。
这是有问题的三个文件:
dev/vt.h
#ifndef _DEV_VT_H_
#define _DEV_VT_H_ 1
#include <stddef.h>
#include <sys/_vt.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct
vt_device_s
{
struct __vt_device_s __device;
size_t cursor_x;
size_t cursor_y;
};
void vt_init(struct vt_device_s *);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _DEV_VT_H_ */
sys/_vt.h
#ifndef _I386__VT_H_
#define _I386__VT_H_ 1
#include <stddef.h>
#include <stdint.h>
#include <dev/vt.h>
#define __VT_WIDTH 80
#define __VT_HEIGHT 25
#define __VT_MEMOFF 0xb8000
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct
__vt_device_s
{
uint16_t *memory;
size_t memory_len;
};
void __vt_init(struct vt_device_s *);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _I386__VT_H_ */
sys/_vt.c
#include <sys/_vt.h>
void
__vt_init(struct vt_device_s *device)
{
device->__device.memory = (uint16_t *) __VT_MEMOFF;
device->__device.memory_len = __VT_WIDTH * __VT_HEIGHT;
}
你的双重包含守卫防止一个文件在被另一个 re-included 时包含自己。解决这个问题的唯一方法是你必须打破这个循环。确定哪个 header 是“更高”的,并将包含“更低”,不要试图从较低的一个中包含较高的。较低的一个必须单独有效。
原因是 pre-processor 必须将多个文件转换为编译器的一个线性行序列。编译器必须先查看一组文件内容。
如果你有这样的循环包含,你可以让代码的最终用户知道谁先出现。如果它们包含文件 A,那么它将包含文件 B,这将尝试再次包含文件 A 但它会被包含守卫阻止,因此 B 的内容将首先被解析。另一方面,如果最终用户首先包含 B,那么编译器将首先看到 A 的内容。
因此,如果您保持原样,那么首先包含哪个文件实际上是随机的。如果你打破这个循环,你可以自己决定先包含哪个。
一旦你决定了,你可以修复关于不完整类型的编译器错误,方法是让你选择放在第一个的文件能够独立存在,然后让第二个使用第一个文件的定义。
对于上下文,我正在编写一个操作系统:
我有一个 struct vt_device_s
和一个 struct __vt_device_s
,它们是特定于体系结构的,位于 vt_device_s
内部,如下所示:
struct
vt_device_s
{
struct __vt_device_s __device;
size_t cursor_x;
size_t cursor_y;
};
现在是架构结构:
struct
__vt_device_s
{
uint16_t *memory;
size_t memory_len;
};
header <dev/vt.h>
知道 <sys/_vt.h>
中定义的 __vt_device_s
因为它包含在内,但我得到这个错误:
error: field '__device' has incomplete type
48 | struct __vt_device_s __device;
|
我意识到这是因为两个文件相互依赖(整个冲突是由 _vt.c
including _vt.h
including vt.h
including _vt.h
引起的)但我不知道怎么理解是编译问题。我在两个文件中都包含了守卫!
PS:我知道如果我使用指针,这将是一个 non-issue,但由于它是一个操作系统,这个 driver 需要在设置分页之前运行(即是,malloc
和 free
还不存在)。
这是有问题的三个文件:
dev/vt.h
#ifndef _DEV_VT_H_
#define _DEV_VT_H_ 1
#include <stddef.h>
#include <sys/_vt.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct
vt_device_s
{
struct __vt_device_s __device;
size_t cursor_x;
size_t cursor_y;
};
void vt_init(struct vt_device_s *);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _DEV_VT_H_ */
sys/_vt.h
#ifndef _I386__VT_H_
#define _I386__VT_H_ 1
#include <stddef.h>
#include <stdint.h>
#include <dev/vt.h>
#define __VT_WIDTH 80
#define __VT_HEIGHT 25
#define __VT_MEMOFF 0xb8000
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct
__vt_device_s
{
uint16_t *memory;
size_t memory_len;
};
void __vt_init(struct vt_device_s *);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _I386__VT_H_ */
sys/_vt.c
#include <sys/_vt.h>
void
__vt_init(struct vt_device_s *device)
{
device->__device.memory = (uint16_t *) __VT_MEMOFF;
device->__device.memory_len = __VT_WIDTH * __VT_HEIGHT;
}
你的双重包含守卫防止一个文件在被另一个 re-included 时包含自己。解决这个问题的唯一方法是你必须打破这个循环。确定哪个 header 是“更高”的,并将包含“更低”,不要试图从较低的一个中包含较高的。较低的一个必须单独有效。
原因是 pre-processor 必须将多个文件转换为编译器的一个线性行序列。编译器必须先查看一组文件内容。
如果你有这样的循环包含,你可以让代码的最终用户知道谁先出现。如果它们包含文件 A,那么它将包含文件 B,这将尝试再次包含文件 A 但它会被包含守卫阻止,因此 B 的内容将首先被解析。另一方面,如果最终用户首先包含 B,那么编译器将首先看到 A 的内容。
因此,如果您保持原样,那么首先包含哪个文件实际上是随机的。如果你打破这个循环,你可以自己决定先包含哪个。
一旦你决定了,你可以修复关于不完整类型的编译器错误,方法是让你选择放在第一个的文件能够独立存在,然后让第二个使用第一个文件的定义。