我正在回答一个问题并注意到一些看似奇怪的事情。有问题的代码更复杂,但观察结果归结为这在MSVC 14.0中编译:
#include <stdio.h>
void foo(int);
int main()
{
foo(66);
getchar();
}
void foo(const char* str, int x)
{
printf("%s %d\n", str, x);
}
此代码产生未定义的行为,因为str
中foo
的值为66
,它不指向有效的以null结尾的字符串,所以在实践中我们(很可能)得到一个段错误。
如上所述,我使用Visual Studio 2015 - MSVC 14.0 - 来编译它。我将代码编译为C.如果我们尝试GCC 5.1,则会失败。
起初我认为这是C早期允许的一个奇怪的事情,并且留在其中不会破坏旧代码(例如隐式函数原型)。但是在这里,我们有一个原型和一个同名的定义,但它们不兼容。为什么编译器不会拒绝这个? C不允许函数重载,因此具有相同名称的两个标识符不合法。
为什么MSVC不拒绝此代码?这种行为有解释吗?这是否明确允许在其中一个标准中使用?
编辑:因为评论中似乎有很多混淆,我想澄清一下。我知道如何避免这些错误,我总是使用最大警告级别编译并将警告视为错误;这不是重点。这个问题纯粹是理论上的:我想知道这种行为是否合法并在C标准中定义。因为两个C编译器在给出相同的代码时表现不同,所以有些错误。
答案 0 :(得分:2)
根据C11(N1570草案)6.7 / 4 声明(在约束条款中):
同一范围内引用同一对象或的所有声明 函数应指定兼容的类型。
该定义也用作声明,因此违反了语言约束。
为此,从5.1.1.3 诊断开始,符合要求的实现有义务生成诊断消息,这是以实现定义的方式:
符合要求的实施应至少产生一种诊断 消息(以实现定义的方式标识)如果a 预处理翻译单元或翻译单元包含一个 违反任何语法规则或约束(...)
这就是全部。诊断信息可以是任何类型,如果他们愿意,他们甚至可能会给你发一封信。