我可以依靠我的编译器来诊断 TU 中的类型不匹配吗?

Can I rely on my compiler to diagnose type mismatches within a TU?

本文关键字:类型 不匹配 TU 我的 依靠 编译器 诊断 我可以      更新时间:2023-10-16

在搜索规范时,似乎我的编译器不需要诊断以下错误

extern int a;
extern float a;

以前认为我的编译器需要诊断这一点,但规范说(我添加了重点)

在对类型进行所有调整之后(在此期间 typedefs (7.1.3) 被其定义替换),引用给定变量或函数的所有声明指定的类型应相同,除了数组对象的声明可以指定因是否存在主数组绑定 (8.3.4) 而不同的数组类型。违反此类型标识规则不需要诊断。

事实上,我发现了编译器不在乎的情况。例如,GCC 和 clang 接受以下内容

void g() { int f(); } 
void h() { float f(); }
由于违反不需要诊断的规则意味着整个程序不再需要诊断

,这意味着以下格式错误的程序也不需要诊断(请参阅 1.4p2)。幸运的是,GCC和Clang都诊断出它们。

int f();
float f();

此代码在翻译时的行为实际上是未定义的。这是什么原因呢?为什么规范不能要求拒绝此类情况并要求对其进行诊断?

我认为你引用的规则是谈论整个程序。如果一个 TU 有extern int a;而另一个 TU 有extern float a;,则不需要诊断,因为单独的翻译使其不可能 - 问题最多只能在链接时检测到。

但是,如果两个声明都发生在单个 TU 中,我确信需要进行诊断。也许是 3.3/4?这(大致)要求一个范围内名称的所有声明都引用同一实体。

对于你的第一个示例,Visual Studio(正确地)启动:

d:experimentstest1test1test1.cpp(7) : error C2371: 'a' : redefinition; different basic types
        d:experimentstest1test1test1.cpp(6) : see declaration of 'a'

您的第二个示例没有错,因为函数定义是本地的,因此它们可以做任何他们喜欢的事情。

你的第三个示例(正确地)在Visual Studio中引发了一个错误:

d:experimentstest1test1test1.cpp(7) : error C2556: 'float f(void)' : overloaded function differs only by return type from 'int f(void)'
        d:experimentstest1test1test1.cpp(6) : see declaration of 'f'
d:experimentstest1test1test1.cpp(7) : error C2371: 'f' : redefinition; different basic types

我确信规范说您不能在同一作用域中有多个同名变量,并且同一作用域中的函数定义必须相差大于其返回类型。

根据 Pete Becker 的说法,当你有像 §1.4/2 中的项目符号这样的规则列表时,它们(至少正常情况下)是按顺序阅读的,早期规则优先于后来的规则。

换句话说,如果代码同时违反了第二个和第三个项目符号点,则违反第二个项目符号点需要发出诊断,即使违反第三个项目符号点似乎消除了该要求。

不幸的是,我从未在标准版中看到过任何明确的声明,只有在Pete的旧Usenet帖子中(如果没记错的话,也许还有Pete之前的编辑Andrew Koenig)。

看起来像是沉重的数学问题。我的猜测是,原因是使用两个不同的 typedef,您最终可能会在两个不同的表达式中使用相同的类型。但是,当编译器存储数据结构时,要求检查将要求编译器将类型表达式"计算"为其正常形式。需要在编译器内部使用丘奇-罗瑟定理来证明这两个表达式是等价的。typedefs 中使用的操作只是普通的旧替换,因此需要完整的教堂罗斯。所以猜猜他们把它变成了可选的。我认为他们不想添加 lambda 演算,接下来需要这样做。

typedef A<int> C;
typedef int D;
typedef A<D> E;
extern C v;
extern E v;

现在,如果不评估两者A<int>,就无法检查它们是否是同一类型。