请记住,typedef
只是类型的替代名称。Linux内核不使用typedef
作为结构类型的原因是有道理的,而您正在证明这一点。
有几种方法可以解决您的问题。我注意到C11允许同一typedef
的多个出现,但我假设您被困在不支持该功能的旧编译器中。
TL;DR
尽管Linux内核不使用typedef
,但我通常使用typedef
,但我大多避免相互引用的结构类型(我无法想到任何使用此类类型的代码)。正如Jens Gustedt在他的答案中所指出的那样,我几乎总是使用以下符号:
typedef struct SomeTag SomeTag
为了使类型名称和结构标记相同(它们位于不同的命名空间中)。在C++中,这个操作是不必要的;当您定义struct SomeTag
或class SomeTag
时,名称SomeTag
成为一种类型名称,无需显式的typedef
(虽然typedef
没有伤害,除了揭示作者在C中比C ++更有经验,或者代码起源为C代码)。
我还观察到,以下划线开头的名称最好被视为“保留给实现”。规则比这复杂一些,但当您使用以下划线开头的名称时,实现有权夺取您的名称,并且在其权利范围内夺取您的名称,因此请勿使用。同样,如果包括任何POSIX标头(例如<stdio.h>
),则POSIX将类型名称结尾_t
保留给实现,而您不是仅在严格的标准C模式下编译。避免创建这样的名称;它们迟早会伤害你。(我还没有修复下面的代码来处理这两个问题:caveat emptor!)。
在下面的代码片段中,我大多忽略了防止多次包含的代码(但您应该在自己的代码中使用它)。
额外标题
typedefs.h:
typedef struct Object Object_t;
typedef struct Klass Klass_t;
klass.h
#include "typedefs.h"
struct Klass
{
void (*_initialize)(Object_t *object, Klass_t *klass);
};
object.h
#include "typedefs.h"
struct Object
{
Klass_t *_klass;
};
这个方法可行是因为在使用前,两个类型名称
Klass_t
和
Object_t
被声明了。
在原型中使用struct Object
klass.h
typedef struct Klass Klass_t;
struct Object;
struct Klass
{
void (*_initialize)(struct Object *object, Klass_t *klass);
};
或者,为了保持一致性,甚至可以使用:
void (*_initialize)(struct Object *object, struct Klass *klass);
object.h
struct Object
{
Klass_t *_klass;
};
这是因为(在广泛的限制内,基本上,如果类型在文件作用域中定义,而不是在函数内部定义),无论所有细节是否完全定义,
struct Object
始终引用相同的类型。
GCC 4.8.2在所有
-std=c89
、
-std=c99
和
-std=c11
下都接受重复的
typedef
,如下所示的代码。它需要
-std=c89 -pedantic
或
-std=c99 -pedantic
才能得到关于重复的
typedef
的错误。
即使没有
-pedantic
选项,GCC 4.5.2也会拒绝此代码;然而,GCC 4.6.0及更高版本在没有
-pedantic
选项的情况下也会接受它。
klass.h
#ifndef KLASS_H_INCLUDED
#define KLASS_H_INCLUDED
typedef struct Klass Klass_t;
typedef struct Object Object_t;
struct Klass
{
void (*_initialize)(Object_t *object, Klass_t *klass);
};
#endif
object.h
#ifndef OBJECT_H_INCLUDED
#define OBJECT_H_INCLUDED
typedef struct Klass Klass_t;
typedef struct Object Object_t;
struct Object
{
Klass_t *klass;
};
#endif
consumer.c
#include "klass.h"
#include "object.h"
Klass_t k;
Object_t o;
您需要决定是否愿意为您的代码承担这种风险 - 可移植性有多重要,必须使其可移植到哪些版本的C(以及哪些C编译器)。