我可以在 C 和 C++ 中可靠地将函数指针设置为 NULL 吗?

Can I reliably set a function pointer to NULL in C and C++?

在P.J。 Plauger 的书 The Standard C Library,他对将函数指针分配给 NULL 提出了警告。

具体来说,他是这样说的:

The macro NULL serves as an almost-universal null pointer constant. You use it as the value of a data-object pointer that should point to no data object declared (or allocated) in the program. As I mentioned on page 216, the macro can have any of the following definitions 0, 0L, or (void *)0.

The last definition is compatible with any data object pointer. It is not, however, compatible with a function pointer. That means you cannot write

int (*pfun) (void) = NULL; /* WRONG */

The translator may complain that the expression type is incompatible with the data object you wish to initialize.

他接着说:

...There is no guarantee, however, that a pointer to void has the same representation as any other (non-character) pointer. It isn't even assignment compatible with function pointers. That means that you can't write NULL as a universal null-pointer constant. Nor can you safely use it as an argument expression in place of an arbitrary data-object pointer.

我已经将函数指针分配给 NULL 很长一段时间了,没有任何问题,我想知道它是否不可移植。

具体来说:

void (*test)() = NULL => 使用 gcc 和 g++ 都可以正常编译

void (*test)() = 0 => 使用 gcc 和 g++ 都可以正常编译

void (*test)() = (void*)0 => 在 gcc 和 g++ 中都产生了无效的转换错误

编辑:void (*test)() = (void*)0在 gcc 中编译良好,我使用的是扩展名为 .cpp 的文件... 尽管 Plauger 说将函数指针分配给 NULL 是错误的,它仍然会始终编译吗?

我不明白的部分是我的 stddef.h:

中 NULL 的定义
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL     /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else   /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0) // this line confuses me
#else   /* C++ */
#define NULL 0
#endif  /* C++ */
#endif  /* G++ */
#endif  /* NULL not defined and <stddef.h> or need NULL.  */
#undef  __need_NULL

这似乎是在 C++ 中将 NULL 定义为 0,在 C 中将其定义为 ((void *)0) 是真的,还是被定义为 __null?

如果是这样,为什么分配给 NULL 一直有效,即使根据 Plauger 的说法,分配给 (void*)0 是“错误的”?**

我对 C89 感兴趣**

void (*test)() = (void*)0 => produced an invalid conversion error in both gcc and g++

GCC 根据文件扩展名检测语言。使用 GCC 编译 .cc 文件将调用 C++ 编译器,而不是 C 编译器。

尝试使用 C 源文件,您会发现它已被接受。应该是,这是标准允许的。

If so, why does assigning to NULL work all the time, but assigning to (void*)0 not?

NULL 在 C++ 模式下不允许定义为 ((void*)0)。在 C++ 模式下,它必须定义为值为 0 的整数常量,或者定义为 nullptr。两者都可以转换为任何函数指针类型。

Can I always reliably set a function pointer to NULL in C and C++?

是的,在任何符合标准的 C 或 C++ 实现中这都有效。

 int (*pfun) (void) = NULL;  

实际上是有效的。

C 的赋值规则是这样说的:

(请注意,这里是初始化,但适用与简单赋值相同类型的约束和转换。)

(C99, 6.5.16.1 Simple assignment p1 Constraints) "One of the following shall hold: [...] — the left operand is a pointer and the right is a null pointer constant;"

(C99, 7.17p3) "The macros are NULL which expands to an implementation-defined null pointer constant;"

因此,C 允许将空指针常量分配给任何指针(对象指针、函数指针或 void *)。请注意,Plauger 的书在提到标准 C 时指的是 C89,但赋值的措辞C89 中的约束相同。