如果两种类型不相同,则导致 C89 中的编译错误

Posted

技术标签:

【中文标题】如果两种类型不相同,则导致 C89 中的编译错误【英文标题】:Cause compilation error in C89 if two types are not the same 【发布时间】:2013-02-05 21:35:22 【问题描述】:

仅使用 C89 的特性,给定

typedef [unspecified token sequence] T1;
typedef [another unspecified token sequence] T2;

展示一种语言结构,当且仅当 T1 和 T2 是相同类型(不仅仅是兼容)时,该语言结构将无错误地编译。对 C89 的限制是因为这将进入 autoconf 探测。

编辑:我需要一个即使 T1 或 T2 或两者都是不完整类型的解决方案。很抱歉之前没有提到这一点。

编辑之子:所有三个当前答案仅检测兼容类型。事实证明,这比我记得的更接近“相同类型”,对于我目前的目的来说足够接近,但出于好奇,我仍在寻找检测 相同 类型的答案。以下是一些兼容但不相同的类型:

typedef void (*T1)(void);
typedef void (*T2)();

typedef float T1[];
typedef float T2[12];

typedef enum  ONE, TWO, THREE  T1;
typedef /* implementation-defined integer type */ T2;

【问题讨论】:

我想编译器警告不够好? @NikosC。如果用-Werror编译,警告会变成错误,所以应该没问题。 出于操作原因,我更希望出现硬错误(不必在 autoconf 探测中使用 CFLAGS),但会发出警告。 见:***.com/questions/9229601/what-is-in-c-code @technosaurus 如果 expression (从技术上讲,一个整数常量表达式)计算结果为某个固定值,则有几种这样的技巧可以使构建失败,但据我所知,它们都不能用于测试 C89 中的 type 相等性。 【参考方案1】:

我认为您应该能够利用 extern 声明的严格类型检查:

typedef int T1;
typedef char T2;

extern T1 t1;    
T2 t1;

以上将无法编译。将 T2 更改为 int 将允许源代码正确构建。

这也不会编译:

typedef int T1;
typedef unsigned int T2;

extern T1 t1;    
T2 t1;

尽管这两种类型都是int。我认为这是您想要的。

但是,这不会触发错误:

typedef emum Foo T1;
typedef unsigned T2;

所以它不是 100% 防水的。但是,必须牢记,enum 不能做任何事情,unsigned 也不能做任何事情。它们具有相同的布局,可以互换使用。实际上,它们是同一类型。

【讨论】:

不错!是的,这就是我想要的行为。在我接受您的回答之前,我将准确检查标准对这个结构的描述,但我很确定您是对的。 在检查 C99 时,如果 T1T2 或两者都是不完整的类型,这将不起作用。这可以通过使t1 的两个声明分别指向T1T2 来解决。此外,从技术上讲,它只要求 T1 和 T2 是 兼容 类型。事实证明,这比我记忆中的“相同类型”更接近,并且可能符合我的目的,但我仍然很好奇是否可以检测到严格的类型相等。 @Zack 我不确定你的意思。如果类型不同,我无法编译它。你能举一个例子,它在类型不同的情况下编译吗? @Zack 没关系,我找到了一个使用 emum 的反例。【参考方案2】:
T1 t1;
T2 *t2 = &t1;

如果 T1 和 T2 不相同,则违反约束。

或者,

T1 f();
T2 f() 

【讨论】:

这些也只检测兼容类型,而不是相同类型。 嗯。后者不应该要求 same 类型,而不仅仅是兼容吗? 函数原型返回类型方法似乎与extern 答案具有相同的结果,包括没有将enumunsigned 视为不同。 对于比 6.7p4 更严格的函数定义,我找不到任何约束(在 C99 中;我没有 C89 的电子副本)“在同一范围内引用的所有声明相同的对象或函数应指定兼容的类型。”并且 6.7.5.3p15 说“对于两个兼容的函数类型,两者都应指定 compatible 返回类型。此外,[...]”(强调我的)。

以上是关于如果两种类型不相同,则导致 C89 中的编译错误的主要内容,如果未能解决你的问题,请参考以下文章

C:标准和编译器中的整数溢出

C99中的restrict和C89的volatilekeyword

踩坑-编译错误:FastJson与lombok导致找不到符号:方法getId()

为啥将 lambda 传递给受约束的类型模板参数会导致“不完整类型”编译器错误?

指针大小为什么与类型无关

java 反编译