【问题标题】:Why can I have conflicting function prototypes and definitions with the same name?为什么同名的函数原型和定义会发生冲突?
【发布时间】:2016-04-21 10:05:17
【问题描述】:

我在回答一个问题时发现了一些奇怪的东西。有问题的代码更复杂,但观察归结为在 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);
}

这段代码会产生未定义的行为,因为foo 中str 的值是66,它不指向有效的以空值结尾的字符串,因此在实践中我们(很可能)会遇到段错误。

如前所述,我使用 Visual Studio 2015 - MSVC 14.0 - 来编译它。我正在编译为 C 的代码。如果我们尝试GCC 5.1,它会失败。

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

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

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

【问题讨论】:

  • 我认为有一个警告......甚至如你所说的 GCC 错误
  • @EugeneSh。很多,但这不会改变任何事情。无效的代码应该被拒绝。
  • 好吧,如果您看到编译器之间的区别 - 它是特定于实现的..
  • @EugeneSh。如果您建议接受非法代码是我们可以称之为“特定于实现”的东西,那么我不得不不同意。当然,除非其中一个标准明确允许这种行为,但无论如何,其中一个编译器做错了。
  • MSVC 的行为可能不太可取,但没关系,因为它会生成诊断消息。 C 标准不知道错误和警告。我们也可能无法告诉您为什么 MSVC 开发人员将其设为警告而不是错误。

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


【解决方案1】:

根据 C11(N1570 草案)6.7/4 声明(在约束部分):

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

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

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

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

就是这样。诊断信息可以是任何类型的,如果他们愿意,他们甚至可以给您发送一封信。

【讨论】:

  • 这就是我所期待的答案。谢谢。
猜你喜欢
  • 2010-12-10
  • 2021-08-28
  • 2014-12-16
  • 2016-04-07
  • 1970-01-01
  • 1970-01-01
  • 2021-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多