C 为什么调用外部函数指针会使程序崩溃?
有两个源文件,C 为什么调用外部函数指针会使程序崩溃?,c,visual-c++,C,Visual C++,有两个源文件,a.c和b.c空调: int main(无效) { foo(); 返回0; } b.c: #包括 静态空心条(空心) { 放(“你好!”); } 外部无效(*foo)(无效)=巴; 将它们一起编译(cla.cb.c),运行程序,程序将崩溃。为什么呢 但是,类似于extern void(*foo)(void)的声明将解决问题 我的环境是Windows MSVC: Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.0
a.c
和b.c
<代码>空调:
int main(无效)
{
foo();
返回0;
}
b.c
:
#包括
静态空心条(空心)
{
放(“你好!”);
}
外部无效(*foo)(无效)=巴;
将它们一起编译(cla.cb.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.
我想这是因为:
由于未声明foo
,编译器猜测它是一个函数
但是,foo
不是函数,而是变量,因此调用失败
由于未声明foo
,编译器猜测它是一个函数。但是,foo
不是函数,而是变量,因此调用失败
在C99(检查请求)之前,C不会强制用户在调用函数之前声明函数,因此编译器不会发出警告或错误;更重要的是,实际上定义了一个foo
,无论它是变量还是函数,因此链接器没有警告或错误。这些使得这个问题很难找到
但是,如中所示,有时这样的隐式函数调用会成为未定义的行为(UB):
J.2未定义的行为
-用于调用作用域中没有函数原型的函数,其中
函数由函数原型定义,或者
prototype以省略号或后面的参数类型结束
升级与参数的类型不兼容
(6.5.2.2)
很抱歉,我意识到被骗是错误的。“C不会强迫用户在调用函数之前声明它们”-实际上它完全是这样,除非你使用的是一个过时的C版本。问题是,在这方面,实现并不总是很好地遵循C标准。@KonradRudolph谢谢你指出这一点,你提醒了我。C99之后有一个限制,我使用的是MSVC1998(像c89一样)。@KonradRudolph C是实现的,而不是标准所说的。只要隐式函数声明是所有广泛使用的C编译器在默认编译模式下接受的语言的一部分,它们就是C的一个特性。告诉人们它们不仅会引起混淆。@zwol我对混淆表示同情,但我坚持“C”是标准。这些实现不是C,而是标准的实现。这很重要,因为标准是规范性的,实现不是。特别是,当出现分歧时,缺陷就出现在实现中,需要在那里修复。如果只有一个主要的实现,那么这将变得不那么重要(或者更重要?),但事实并非如此。@KonradRudolph在编译器上提交错误报告时,这是一个很好的策略,但我们现在不这么做。当向初学者教授C语言时,这就是我们在这里所做的——在这个问题上没有语言律师的标签——你必须采取更务实的观点。