c中的结构标签兼容性

structure tag compatibility in c

我读到从 C99 开始,在不同文件中定义的两个完整 struct 必须具有相同的标记才能兼容。

所以我写了下面的代码:

file1.c:

/* file1.c */
#include <stdio.h>

typedef struct tag1 { int foo; } type1;
type1 a; 
void func(void);

int main() {
    printf("a.foo : %d\n", a.foo); 
    func();
    printf("a.foo : %d\n", a.foo); 
    return 0;
}

file2.c:

/* file2.c */
typedef struct tag2 { int foo; } type2; 
type2 a;
void func(void) {
    a.foo = 100;
}

并期望两个 a 被认为是不同的,因此两个 printf 都打印 a.foo : 0 但输出是:

a.foo : 0
a.foo : 100

这是为什么?

关于类型问题,C标准中的规定是这样的:

  • 如果你在两个文件中使用相同的结构标签声明a那么你的程序将工作(在这个尊重)。

请注意,C 标准并未说明如果违反“如果”部分会发生什么情况。在那种情况下,C 标准并没有说你的程序会工作,它没有说你的程序不会工作,它没有说会有错误信息,它没有说不会有错误信息。它什么也没说。

程序中还有一个问题:type1 a;type2 a;a暂定,根据C标准,解决定义。那么a定义在多个翻译单元中,违反了C 2018 6.9 5:

… If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof or _Alignof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

但是,假设您的 C 实现定义了这些以将它们解析为单个对象,就像 Unix 上的 C 实现通常所做的那样。我们只会考虑类型问题。

那么您正在使用两个不兼容的类型访问对象 a。这违反了 C 2018 6.5 7:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:…

其中 none 列出的类型在这种情况下得到满足。 C 2018 4 2 告诉我们这个违规的后果是什么:

If a "shall" or "shall not" requirement that appears outside of a constraint or runtime-constraint is violated, the behavior is undefined…

而 C 2018 3.4.3 告诉我们这意味着什么:

behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this document imposes no requirements

就是这样:由于类型冲突,C 标准对 C 实现没有任何要求。该标准允许您的实现(编译器、链接器、库、操作系统、硬件以及构建和 运行 C 程序所需的任何其他东西)接受您的程序,拒绝您的程序,运行 您的程序,拒绝 运行 你的程序,警告你,不警告你,让你的程序行为不端,等等。该标准对必须发生的事情只字不提。