本周我们在这里遇到了一个有趣的问题。
我们在哈佛架构嵌入式平台上使用 C 语言工作,该平台具有 16 位数据地址和 32 位代码地址。
当您使用函数指针时会出现此问题。如果你有像
这样的代码if (fp) fp();
或
if (fp != 0) fp();
一切都很好。
但是如果你有这样的代码
if (fp != NULL) fp();
然后,因为 NULL
被定义为 (void *) 0
,编译器(在本例中为 gcc)a) 不发出警告 b) 执行 16-与您的函数指针进行位比较,而不是 32 位比较。只要您的函数指针不恰好位于 64k 边界上就可以,因此所有底部 16 位都为 0。
目前我们有大量代码包含针对 NULL 的显式检查。其中大部分将是数据指针,但其中一些将是函数指针。 != NULL
或 == NULL
的快速 grep 揭示了 3000 多个结果,许多人需要手动检查。
所以,我们现在想要的是
找到所有比较函数指针(但不是数据指针)的情况的方法(因此我们可以让它们与我们定义为 32 位 0 的 FP_NULL 进行比较),或
以正确的方式重新定义 NULL。
(或者,我想, 更新我们的 gcc 端口以检测和 正确处理这种情况)。
我想不出任何适用于 1 的方法。对于 2,我能想到的唯一方法是将 NULL 重新定义为 0 函数指针,这对于绝大多数针对数据的比较来说是非常浪费的指针。 (32 位比较是 4 条指令,16 位比较是 1 条指令)。
有什么想法或建议吗?
最佳答案
在我看来,最简单的方法是将所有出现的 NULL
替换为 0
。这适用于函数指针(如您所说)和对象指针。
这是 (2) 将 NULL 重新定义为普通 0
的变体。
但是您不能将函数指针与 NULL
进行比较这一事实是您实现中的一个错误。 C99 声明空指针常量的比较对于对象和函数指针都是可能的,并且 NULL 应该扩展到这个常量。
C-FAQ 问题的小补充 5.8 :
Q: Is NULL valid for pointers to functions?
A: Yes (but see question 4.13)
混合函数指针与(void *) 0
(对 R.. 评论的回复)。我相信一起使用函数指针和 (void *) 0
是明确定义的。在我的推理中,我将引用 C99 草案 1256 的部分内容,但不会引用大部分内容以保持其可读性。 C89应该也适用。
- 6.3.2.3 (3) 定义整型常量表达式
0
和这样一个转换为(void *)
的表达式作为空指针常量 .并且:“如果一个空指针常量被转换为一个 指针类型,生成的指针称为空指针,保证比较不相等 指向任何对象或函数的指针。” - 6.8.9 为指针操作数和空指针常量定义了
==
和!=
操作数。对于这些:“如果一个操作数是指针而另一个是 空指针常量,空指针常量转换为指针的类型。”
结论:在fp == (void *) 0
中,空指针常量被转换为fp
的类型。此空指针可以与 fp
进行比较,如果它指向一个函数,则保证不等于 fp
。 Assignment (=
) 有一个类似的子句,所以 fp = (void *) 0;
也是定义良好的 C。
关于c - 哈佛架构平台上的 NULL 指针问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3889541/