【问题标题】:Why does calling external function pointer crash the program?为什么调用外部函数指针会使程序崩溃?
【发布时间】:2020-09-05 16:53:42
【问题描述】:

有两个源文件,a.cb.ca.c:

int main(void)
{
    foo();
    return 0;
}

b.c:

#include <stdio.h>

static void bar(void)
{
    puts("Hola!");
}

extern void (*foo)(void) = bar;

一起编译(cl a.c b.c),运行程序,程序会崩溃。这是为什么呢?

但是,像extern void (*foo)(void); 这样的声明可以解决问题。

我的环境是 Windows MSVC:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

我猜是因为:

  1. 由于没有声明foo,编译器猜测它是一个函数。
  2. 但是foo不是函数,而是变量,所以调用失败。

【问题讨论】:

  • 对不起,我意识到这个骗局是错误的。

标签: c visual-c++


【解决方案1】:

由于没有声明foo,编译器猜测它是一个函数。但是foo不是函数,而是变量,所以调用失败。

在 C99 之前(请求检查),C 不强制用户在调用函数之前声明函数,因此编译器不会发出警告或错误;更重要的是,确实定义了一个foo,无论是变量还是函数,因此链接器没有警告或错误。这些使这个问题很难找到。

但是,正如在 this SO post 中发现的那样,有时像这样的隐式函数调用会变成未定义的行为 (UB):

J.2 未定义行为

——用于调用一个在作用域中没有函数原型的函数 该函数是用函数原型定义的,要么 原型以省略号或后面的参数类型结尾 促销与参数的类型不兼容 (6.5.2.2)。

【讨论】:

  • “C 不会强制用户在调用函数之前声明它们”——实际上它完全可以,除非你使用的是一个非常过时的 C 版本。问题是 实现 在这方面并不总是很擅长遵循 C 标准。
  • @KonradRudolph 谢谢你指出这一点,你提醒我。 C99 之后有限制,我使用的是 MSVC 1998(如 c89)。
  • @KonradRudolph C 是实现的,而不是标准所说的。只要隐式函数声明是所有广泛使用的 C 编译器在默认编译模式下接受的语言的一部分,它们就是 C 的一个特性。告诉人们它们不是只会引起混淆。
  • @zwol 我对这种混淆表示同情,但我坚信“C”是标准。实现不是 C,它们是标准的实现。这很重要,因为标准是规范性的,而实施却不是。特别是,当存在分歧时,缺陷就在在实现中,需要在那里进行修复。如果只有一个主要实现,这将不那么重要(或更多?)......但事实并非如此。
  • @KonradRudolph 在提交有关编译器的错误报告时,这是一个很好的策略,但这不是我们在这里所做的。在向初学者教授 C 时,我们在这里所做的——在这个问题上没有语言律师标签——你必须采取更务实的观点。
猜你喜欢
  • 1970-01-01
  • 2020-04-06
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-12
相关资源
最近更新 更多