通过 "myPtr > 0" 检查空指针

Null pointer check via "myPtr > 0"

在一些遗留代码中,我遇到了以下空指针检查

if( myPtr > 0 ) {
...
}

通过此 if-check 检查空指针是否存在任何技术风险?

指针和整数之间的有序比较在 C++ 中是 ill-formed(即使整数是空指针常量,例如在本例中)。风险在于编译器被允许并且确实拒绝编译此类代码。


您可以将其重写为以下任一形式:

if(myPtr != nullptr)
if(myPtr)

0 是一个 NULL 常量。所以这相当于 ptr > (void*)0.

问题是 C++ 中指针的 > 仅对指向同一对象或数组的指针有效。这条规则起源于过去,当时像分段内存这样相对疯狂的东西更常见,但它允许编译器进行优化和假设。

例如,假设 px 是指向数组的指针,并且它当前指向第一个元素。那么 px>py 为真,除非 py 也是指向第一个元素的指针。或者,如果 px 是指向数组 one-past-the-end 的指针,则 px<py 始终为 false。

使用这种知识,编译器可以理解重构和重写循环边界,这反过来可以让编译器生成更快的代码。

但这也意味着 px>py 可能在一个地方为真而在另一个地方不为真,因为编译器可以在一个地方证明关于 py 的事实,但不能在另一个地方证明。

简而言之,指针比较要非常小心。

同时,null 和任何其他指针之间的相等性已明确定义。

也保证std::less行为良好,在定义<时同意<;这允许指针映射工作。

在这种情况下,正确的重写是:

if(myPtr!=nullptr)

如果 myPtr 不是指针,或者

将无法编译
if(myPtr)

如果 myPtr 是带符号的数字类型,则存在您刚刚更改行为的风险。我会做第一个。

正如其他人所说,比较无效,因此行为取决于编译器。许多操作系统可能认为指针是有符号的,因为它们将地址 space 分成两半,负数属于内核,因此那里的编译器可能会为 myPtr > 0

发出带符号的比较

有几个案例我看到编译器认为指针是带符号的,但我现在找不到它们。但一个值得注意的例子是 POINTER_SIGNED and POINTER_UNSIGNED macros in Windows which resolves to __sptr and __uptr

另见

  • comparing pointer to a negative value
  • Must allocated memory address be positive in user space of all platforms
  • Pointer comparisons in C. Are they signed or unsigned?