例如,由于可能的对齐,指向不同类型的指针不能直接相互转换(也许不是完全正确的陈述,但你还是不明白我的想法)。是否有类似的技术原因导致您不能执行以下操作:
struct A
{
int a, b;
} ;
struct B
{
int a, b;
} ;
void func(struct A a, struct B b)
{
a = b;
}
现在删除我并编辑这个问题,如果你理解它(在一些奇怪的情况下)并将它翻译给公众。
例如,由于可能的对齐,指向不同类型的指针不能直接相互转换(也许不是完全正确的陈述,但你还是不明白我的想法)。是否有类似的技术原因导致您不能执行以下操作:
struct A
{
int a, b;
} ;
struct B
{
int a, b;
} ;
void func(struct A a, struct B b)
{
a = b;
}
现在删除我并编辑这个问题,如果你理解它(在一些奇怪的情况下)并将它翻译给公众。
在 c 中,具有相同上下文的两个不同结构何时可以真正创建不同的类型?
他们总是这样做。 struct A
并且struct B
是不同的类型。
struct A {
int a, b;
} ;
struct B {
int a, b;
} ;
禁止这样做的原因纯粹是因为它对编译器来说太复杂了,还是其他原因?
对于编译器来说并不太复杂。最好将它们分开。如果需要相同,代码可以使用typedef
.
typedef struct A foo;
typedef struct A bar;
int main(void) {
foo1 x;
bar1 y = x;
struct B z = x; // does not compile
}
为什么不允许struct B z = x;
?那就是语言设计。如果防止像下面这样的愚蠢代码。尽管struct JustLikeFILE
具有与 相同的字段,但从FILE
概念上讲它不是FILE
.
void f(void) {
FILE *f = fopen("abc","r");
struct JustLikeFILE g = *f; // does not compile
}
C 标准定义了“类型兼容性”,并且对于要兼容的结构类型,除其他标准外,它们必须使用相同的标签。你的结构使用不同的标签——它们本质上是不同的类型。
您可以在标准中一些措辞复杂的规范中找到肮脏的细节:
ISO/IEC 9899:2011 §6.2.7 兼容型和复合型
如果它们的类型相同,则两种类型具有兼容的类型。用于确定两种类型是否兼容的附加规则在 6.7.2 中描述了类型说明符,在 6.7.3 中描述了类型限定符,在 6.7.6 中描述了声明符。55)此外,如果它们的标记和成员满足以下要求,则在单独的翻译单元中声明的两种结构、联合或枚举类型是兼容的:如果用标记声明一个,则另一个应用相同的标记声明。如果两者都在各自翻译单元内的任何地方完成,则适用以下附加要求:它们的成员之间应存在一一对应关系,使得每对对应的成员都声明为兼容类型;如果该对的一个成员使用对齐说明符声明,则另一个成员使用等效的对齐说明符声明;如果该对中的一个成员声明了一个名称,则另一个成员声明为相同的名称。对于两个结构,相应的成员应以相同的顺序声明。对于两个结构或联合,相应的位域应具有相同的宽度。对于两个枚举,对应的成员应具有相同的值。
55)两种类型不必相同才能兼容。
由于您的两个示例结构具有不同的标签(struct A
, struct B
),因此它们显然不是兼容的类型。
您的第二个示例使用两种匿名struct
类型:
struct { int a, b; } func1();
void func2()
{
struct { int a, b; } var = func1(); //not allowed
}
标准的不同部分适用于此:
6.7.2.1 结构和联合说明符
¶8 struct-or-union-specifier 中 struct-declaration-list 的存在在翻译单元内声明了一个新类型。struct-declaration-list 是结构或联合成员的一系列声明。
引用的struct-declaration-list是大括号中的部分{
... }
。由于您在一个翻译单元中有两个,它们声明(定义)两种类型,因此不兼容。
您的最后一个示例,typedef int myOrangeInt;
并typedef int myAppleInt;
说明了typedef
在 C 中没有引入新类型;它只是引入了另一种类型的同义词。在这种情况下,myOrangeInt
是 的同义词int
, 也是myAppleInt
,并且由于它们是同一类型的同义词,因此类型是同一类型。
§6.7.8 类型定义
¶3 …
typedef
声明不会引入新类型,只是指定类型的同义词。…</p>