为什么匿名结构会导致类型冲突

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.xs.y,而不是 s.something.xs.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 值的结构,我们用于平面中的点(xy 坐标):

typedef struct { double d[2]; } ComplexNumber;
typedef struct { double d[2]; } Point;

让编译器将它们视为不同的类型意味着它可以向我们发出错误警告,例如将 Point 作为参数传递给期望 Complex 的地方。

正如您所注意到的,typedef 为类型创建了一个新名称。然后使用 typedef 名称引用该现有类型。它不会“重复” struct 的声明并创建新类型。