空函数指针

16
调用空函数指针的行为是什么?
void (*pFunc)(void) = NULL;  
pFunc();

为什么建议将未使用的函数指针初始化为NULL?

1
就像普通指针一样,我认为你会得到一个段错误。 - Rerito
1
http://stackoverflow.com/questions/10014284/what-does-null-function-pointer-in-c-mean - Suri
1
这两个指针指向同一个问题 :-) - Philip Kendall
3个回答

15
在C和C++中,这被称为“未定义行为”,这意味着它可能会导致“分段错误”、无输出或者其他一些基于您的编译器、运行此代码的操作系统、环境等因素造成的情况。
将函数指针初始化为NULL或将指针初始化为NULL有助于某些开发人员确保其指针未初始化且不等于随机值,从而防止意外解引用。

1
这将在99%的情况下导致分段错误,并且在许多系统/架构上也是如此。然而,标准并没有明确说明它会发生。 - Halim Qarroum
@VladLazarenko: C和C++都称这是“未定义行为”,也就是说,任何事情都可能发生。如果那个地址恰好是“可执行”的,那么它很有可能会被执行……但也可能不会被执行。我记得有一段时间前,Linux内核的一个漏洞正好基于这个区别…… - rodrigo
1
@rodrigo:没错。我想知道的是,是否有一个标准明确规定0x0不能作为有效的内存地址。如果是这样,那么它将是“未定义行为”。如果没有这样说,那么它将是未指定的 - 这两者本质上是不同的。 - user405725
2
@VladLazarenko:标准对地址0x0没有任何说明。关于“NULL”指针,它只说了两件事:没有有效的对象或函数具有地址“NULL”,引用/调用“NULL”指针是未定义行为。现在,实现可以选择记录特定行为,甚至可以指定“NULL”指针的二进制值。有关更好的解释,请参见此其他问题 - rodrigo
5
@vonbrand: 你是正确的:文字字面上的“0”可以用作“NULL”指针常量。但这并不意味着空指针在地址0x0处,或者它是一个全零的位模式。实际上,空指针的地址是由具体实现定义的。虽然有点令人困惑,但就是这样。 - rodrigo
显示剩余2条评论

2

当您尝试访问NULL时会发生什么? 以下是关于数据和代码的真相,以及当您尝试读取NULL(或0到4096之间的任何地址,即至少段的第一页)时会发生的情况。其根本原因在于操作系统和微处理器的分段/分页架构。 当您尝试访问任何数据或代码的NULL(或0)地址时,它会导致分段错误(实际上是致命的页错误)。部分的第一页被视为虚拟地址空间的无效部分或无效部分。这是故意保持第一页无效(或不存在),以便在程序执行时,指针包含的至少一个地址可以表示为无效。 第一页的页描述符(其中包含虚拟地址0,NULL)的第一位“present”为0(表示其为无效页)。现在,如果您尝试访问NULL指针(0地址),它将导致引发页面错误,因为页面不存在,操作系统将尝试处理此页面错误。当页面错误处理程序看到它正在尝试访问第一页时,该页被视为虚拟地址空间的无效部分,它就会杀死进程。这就是用户空间进程的全部内容。如果您尝试在系统进程(内核级代码)中访问NULL指针,它将使您的操作系统失败并导致系统崩溃。 链接:http://en.wikipedia.org/wiki/Page_fault#Invalid http://en.wikipedia.org/wiki/Memory_protection#Paged_virtual_memory http://pdos.csail.mit.edu/6.828/2005/readings/i386/s05_02.htm 以上足够了,但我认为您也应该阅读这篇文章http://www.iecc.com/linker/linker04.txt 为什么函数指针初始化为NULL? 尽管如果您尝试使用NULL调用函数将导致页面/段错误。NULL表示其为无效函数。如果它包含任何垃圾地址,但在代码部分的有效虚拟地址空间中,则认为将调用该地址上的任何代码,这可能会更加灾难性(特别是在实时系统中)。将funcp = funct_foo_name + 1初始化;现在使用函数指针调用函数。函数指针指向代码部分的有效虚拟地址空间。但函数将从不正确的位置开始执行。这可能导致错误的代码执行或错误的顺序。

1
你做了太多不必要的假设。我曾经在一些平台上工作过,其中地址0和地址42890没有任何区别。 - Nik Bougalis
1
正如《十诫》所教导的,“不可追踪空指针,因为混乱和疯狂等待着你的结局。” - vonbrand
@NikBougalis:你说得对。我所指的第一页或无效地址范围0到4096(这是x386标准页面大小)是初始无效虚拟地址空间。我认为这是一个与操作系统相关的问题,它认为多少初始虚拟地址空间范围是无效的。 - rahul.deshmukhpatil

0

出于与初始化“普通”(数据)指针为NULL相同的原因,建议这样做:因为它可能使一些错误更容易被追踪。当然,对于这是否有用的看法因人而异 :-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接