检查指针是不是为空,然后在同一个 if 语句中取消引用它是不是安全?

Posted

技术标签:

【中文标题】检查指针是不是为空,然后在同一个 if 语句中取消引用它是不是安全?【英文标题】:Is it safe to check if a pointer is null, then dereference it in the same if statement?检查指针是否为空,然后在同一个 if 语句中取消引用它是否安全? 【发布时间】:2012-11-26 18:50:16 【问题描述】:

如果传入空指针,下面的代码是否安全?

if(ptr && *ptr == value)

   //do something

检查的顺序重要吗?改成这个有效果吗?

if(*ptr == value && ptr)

   //do something

【问题讨论】:

我已经编辑了问题标题,以澄清“有效指针”的意思是“非空”。 【参考方案1】:

如果指针无效(或者更确切地说是NULL,正如指出的那样),在第一个版本中short-circuiting 将阻止对*ptr == value 的评估,所以第一个是安全的。

第二个总是访问*ptr,不管它是否有效。

【讨论】:

if (ptr) 无法检查 invalid 指针。它只能检查 null 指针。 @KerrekSB 我假设“无效”在这里指的是“NULL”。除此之外,您必须知道,在 C++ 中检测指向无处的指针是相当困难的。 根据您阅读标准的方式,空指针实际上可能是一个完美的有效指针。我更喜欢将“无效指针”一词保留为不再存在的对象的地址或非法指针运算的结果。该标准有一个关于“安全派生指针”(3.7.4.3)的部分。【参考方案2】:

是的 (1) 是安全的,因为短路。这是评估逻辑语句的方式。如果&& 语句的第一部分为假,则整个语句永远不会为真,因此它不会尝试评估第二部分。

和 (2) 是不安全的,因为它首先取消引用空指针,这是未定义的行为。

编辑:

参考下面的 KerrekSBs 评论: Why dereferencing a null pointer is undefined behaviour?

来自该帖子的第一个答案:

为取消引用 NULL 指针定义一致的行为将 要求编译器在每个之前检查 NULL 指针 大多数 CPU 架构的取消引用。这是一个不能接受的 为速度而设计的语言的负担。

还有(历史上是)硬件,其中NULL(并非总是0)指向的内存实际上在程序中是可寻址的并且可以取消引用。因此,由于缺乏共识和一致性,决定取消引用空指针将是“未定义的行为”

【讨论】:

(2) 不只是“不安全”;这是彻头彻尾的未定义行为 @KerrekSB:你最好详细说明一下你提出的区别。 @Mehrdad:嗯,gets 不安全,因为您不知道所需的缓冲区长度,而printf 不安全,因为您可以传递错误类型的参数。 “不安全”是指无法静态验证代码的正确性。这与取消引用空指针完全不同,后者总是很糟糕。 物理上,空指针不一定绑定到地址0。它可以由任何特定于平台的地址表示。 @KerrekSB:从技术上讲,这并不“总是”不好,对吧?实现很可能会确定它是该特定系统的有效操作,在这种情况下它将是完全安全的......它不像标准 要求 它是未定义的行为。所以我并没有真正看到“不安全”和“未定义”之间的显着区别(尽管正如你提到的那样它肯定是无法验证的)。【参考方案3】:

前者正确安全,后者不正确。

内置的&& 运算符具有短路语义,这意味着当且仅当第一个参数为真时才计算第二个参数。

(对于 重载 运算符,情况并非如此。)

【讨论】:

感谢未定义的行为指针 - 我从事实践已经很长时间了,并且经常对细节缺乏兴趣 - 我现在正在尝试补救。【参考方案4】:

除了所有其他关于ptr && *ptr == value 有效但不是相反的答案之外,有效指针的概念可能具有不同的含义。

ptr 可能是一个未初始化的变量,或者可以通过不指向任何地方(例如 dangling pointer)但不是空。

在这种情况下,测试顺序都不起作用。

一些指针可能是无效的并且是非空的(那么测试ptr && *ptr == value未定义的行为)。没有可移植的方法来测试它们。 (但您可以使用操作系统或处理器特定的技巧)。

【讨论】:

以上是关于检查指针是不是为空,然后在同一个 if 语句中取消引用它是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

如何在javascript中执行if语句来检查JSON数组是不是为空?

IF 语句中的 jQuery OR 运算符检查任一文本字段是不是为空

如何制作 if 语句来检查所有或仅一个文本字段是不是为空

Vue v-if 语句检查变量是不是为空或 null

如何在 Perl 中检查多个变量是不是为空

在 Net6 IF 语句中取消引用可能为空的引用