为什么匿名结构会导致类型冲突
Why do anonymous structs cause conflicting types
#define MyStruct(T) struct {T data;}
void foo(MyStruct(int) s);
void foo(MyStruct(int) s) {
return;
}
int main(void) {
//...
return 0;
}
这会导致错误:
main.c:7:6: error: conflicting types for 'foo'
void foo(MyStruct(int) s) {
^
main.c:5:6: note: previous declaration is here
void foo(MyStruct(int) s);
^
如果我创建一个 typedef,例如 typedef MyStruct(int) MyIntStruct;
并使用它,就没有错误。
所以我的问题是,为什么会出现类型冲突错误?是否所有匿名结构都是唯一的,就像编译器不会确定它们是否完全相同?
首先,这些是没有标签的结构声明,不是匿名结构。 匿名结构 是没有名称的结构,而不是没有标签的结构声明。例如:
struct outer
{
struct inner { int x; int y; };
int z;
} s;
这段代码中,s
里面的struct
成员没有成员名,所以是匿名的。我们没有可以引用该结构的名称,我们将其成员称为 s.x
和 s.y
,而不是 s.something.x
和 s.something.y
。
每个不带标签的结构声明都声明不同类型的原因是 C 2018 6.7.2.3 5 说:
… Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type.
原因是有时我们出于不同目的使用具有相同内容的结构。例如,我们可能有一个包含两个 double
值的结构,我们用于复数(实部和虚部)和一个包含两个 double
值的结构,我们用于平面中的点(x 和 y 坐标):
typedef struct { double d[2]; } ComplexNumber;
typedef struct { double d[2]; } Point;
让编译器将它们视为不同的类型意味着它可以向我们发出错误警告,例如将 Point
作为参数传递给期望 Complex
的地方。
正如您所注意到的,typedef
为类型创建了一个新名称。然后使用 typedef
名称引用该现有类型。它不会“重复” struct
的声明并创建新类型。
#define MyStruct(T) struct {T data;}
void foo(MyStruct(int) s);
void foo(MyStruct(int) s) {
return;
}
int main(void) {
//...
return 0;
}
这会导致错误:
main.c:7:6: error: conflicting types for 'foo'
void foo(MyStruct(int) s) {
^
main.c:5:6: note: previous declaration is here
void foo(MyStruct(int) s);
^
如果我创建一个 typedef,例如 typedef MyStruct(int) MyIntStruct;
并使用它,就没有错误。
所以我的问题是,为什么会出现类型冲突错误?是否所有匿名结构都是唯一的,就像编译器不会确定它们是否完全相同?
首先,这些是没有标签的结构声明,不是匿名结构。 匿名结构 是没有名称的结构,而不是没有标签的结构声明。例如:
struct outer
{
struct inner { int x; int y; };
int z;
} s;
这段代码中,s
里面的struct
成员没有成员名,所以是匿名的。我们没有可以引用该结构的名称,我们将其成员称为 s.x
和 s.y
,而不是 s.something.x
和 s.something.y
。
每个不带标签的结构声明都声明不同类型的原因是 C 2018 6.7.2.3 5 说:
… Each declaration of a structure, union, or enumerated type which does not include a tag declares a distinct type.
原因是有时我们出于不同目的使用具有相同内容的结构。例如,我们可能有一个包含两个 double
值的结构,我们用于复数(实部和虚部)和一个包含两个 double
值的结构,我们用于平面中的点(x 和 y 坐标):
typedef struct { double d[2]; } ComplexNumber;
typedef struct { double d[2]; } Point;
让编译器将它们视为不同的类型意味着它可以向我们发出错误警告,例如将 Point
作为参数传递给期望 Complex
的地方。
正如您所注意到的,typedef
为类型创建了一个新名称。然后使用 typedef
名称引用该现有类型。它不会“重复” struct
的声明并创建新类型。