为什么我可以使用相同名称的冲突函数原型和定义?

时间:2016-01-15 18:23:37

标签: c visual-c++ function-prototypes

我正在回答一个问题并注意到一些看似奇怪的事情。有问题的代码更复杂,但观察结果归结为这在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);
}

此代码产生未定义的行为,因为strfoo的值为66,它不指向有效的以null结尾的字符串,所以在实践中我们(很可能)得到一个段错误。

如上所述,我使用Visual Studio 2015 - MSVC 14.0 - 来编译它。我将代码编译为C.如果我们尝试GCC 5.1,则会失败。

起初我认为这是C早期允许的一个奇怪的事情,并且留在其中不会破坏旧代码(例如隐式函数原型)。但是在这里,我们有一个原型和一个同名的定义,但它们不兼容。为什么编译器不会拒绝这个? C不允许函数重载,因此具有相同名称的两个标识符不合法。

为什么MSVC不拒绝此代码?这种行为有解释吗?这是否明确允许在其中一个标准中使用?

编辑:因为评论中似乎有很多混淆,我想澄清一下。我知道如何避免这些错误,我总是使用最大警告级别编译并将警告视为错误;这不是重点。这个问题纯粹是理论上的:我想知道这种行为是否合法并在C标准中定义。因为两个C编译器在给出相同的代码时表现不同,所以有些错误。

1 个答案:

答案 0 :(得分:2)

根据C11(N1570草案)6.7 / 4 声明(在约束条款中):

  

同一范围内引用同一对象或的所有声明   函数应指定兼容的类型。

该定义也用作声明,因此违反了语言约束

为此,从5.1.1.3 诊断开始,符合要求的实现有义务生成诊断消息,这是以实现定义的方式:

  

符合要求的实施应至少产生一种诊断   消息(以实现定义的方式标识)如果a   预处理翻译单元或翻译单元包含一个   违反任何语法规则或约束(...)

这就是全部。诊断信息可以是任何类型,如果他们愿意,他们甚至可能会给你发一封信。