c语言 - 假设 NULL 常量为零是否安全



理查德·里斯(Richard Reese)的《理解和使用C指针》一书说:

概念是空指针支持的抽象 不断。此常量可能是也可能不是常数零。一 C 程序员不需要关心他们的实际内部 表示法。

我的问题是,既然"这个常数可能是也可能不是常数零",那么在我的代码中做下面这样的事情对我来说是否安全:

int *ptr = NULL;
// Some code which probably sets ptr to a valid memory address
if(!ptr)
{
ERROR();
}

如果 NULL 不为 0,则 if 子句的计算结果有可能为 true。

假设 NULL 常量为零是否安全?

NULL将比较等于0.
NULL通常是零位模式。NULL可能是非零位模式 - 但如今看不到。


OP 混合了至少 4 件事:NULL空指针常量空指针、将空指针与 0 进行比较。 C 不定义NULL 常量

NULL

NULL是一个宏"它扩展到实现定义的空 指针常量" C17dr § 7.19 3

空指针常量

值为 0 的整数常量表达式或此类表达式 强制转换为类型void*,称为空指针常量。C17dr § § § 6.3.2.3 3

因此,空指针常量的类型可以是intunsignedlong、...或void *.

当整数常量表达式1时,空指针常量为 0。 作为像((void *)0)这样的指针,它的值/编码没有指定。 它普遍具有零的位模式,但没有指定。

可能有许多空指针常量。 它们彼此比较相等。

注意:当空指针常量为整数时,它的大小可能与对象指针的大小不同。 通常通过根据需要附加一两个L后缀来避免这种大小差异。

空指针

如果将空指针常量转换为指针类型,则 生成的指针(称为空指针)保证可以比较 不等于指向任何对象或函数的指针。 C17dr § § 6.3.2.3 3

将空指针转换为另一种指针类型将生成空 该类型的指针。任何两个空指针的比较应相等。C17dr § § 6.3.2.3 4

空指针的类型是一些指针,可以是对象指针(如int *, char *)或函数指针(如int (*)(int, int)void *)。

未指定空指针的值。 它普遍具有零的位模式,但没有指定。

所有空指针都相等,无论其编码如何。

空指针与 0 进行比较

if(!ptr)if(!(ptr != 0))相同。 当指针ptr(一个空指针)与 0 进行比较时,零将转换为指针,即相同类型的空指针int *。 这两个空指针可能具有不同的位模式,比较相等。


那么,当假设 NULL 常量为零是不安全的吗?

NULL可能是((void*)0),其位模式可能与零不同。 无论其编码如何,它都会像上面一样比较等于 0。 已经讨论了召回指针比较,而不是整数比较。将NULL转换为整数可能不会导致整数值为 0,即使((void*)0)都是零位。

printf("%jun", (uintmax_t)(uintptr_t)NULL); // Possible not 0

请注意,这是将指针转换为整数,而不是将 0 转换为指针的if(!ptr)的情况。

C 规范包含许多旧的做事方式,并对新颖的新方式持开放态度。 我从未遇到过NULL不是全零位模式的实现。 鉴于存在许多假设NULL都是零位的代码,我怀疑只有旧的晦涩实现曾经使用过非零位模式NULL并且NULL几乎可以肯定是全零位模式。


1空指针常量为 1) 整数或 2)void*。 "当整数..."是指第一种情况,而不是像(int)((void*)0)那样对第二种情况进行铸造或转换。

if(!ptr)是检查 NULL 指针的安全方法。

表达式!x完全等效于0 == x。 常量0是 NULL 指针常量,可以将任何指针与NULL 指针常量进行比较以使其相等。

即使空指针的表示形式不是"所有位 0",也是如此。

C 标准关于!运算符的第 6.5.3.3p5 节规定:

逻辑否定运算符!的结果为 0,如果 其操作数的值比较不等于 0,如果其值为 1 操作数比较等于 0。 结果的类型为int。这 表达式!E等效于(0==E)

关于指针转换的第 6.3.2.3p3 节指出:

值为 0 的整数常量表达式,或类似的 转换为类型void *的表达式称为空指针 常数。如果将空指针常量转换为指针类型, 生成的指针(称为null 指针)保证可以比较 不等于指向任何对象或函数的指针。

Chux 写了一个很好的、详细的答案,但具体到那本书,我对它的质量持怀疑态度:

  • 此常量可能是也可能不是常数零

    这是错误的,它必须始终是零或零投到void*.空指针常量的定义可在 C17 6.3.2.3/3 中找到:

    值为 0 的整数常量表达式,或强制转换为类型的此类表达式 void * 称为空指针常量。如果将空指针常量转换为 指针类型,生成的指针,称为空指针,保证比较不相等 指向任何对象或函数的指针。

    这意味着所有整数常量表达式如00L0u0x0''等都是空指针常量。如果它们中的任何一个被强制转换为void*,它也是一个空指针常量。

  • C程序员不需要关心他们实际的内部表示。

    作者显然混淆了空指针常量空指针这两个形式术语。程序员不需要关心空指针的内部表示。不过,他们确实需要知道是什么使有效的空指针常量。最安全、最易读的方法是使用NULL宏,它保证为 null 指针常量。

因此,关于您的问题"在我的代码中执行如下所示的操作对我来说是否安全" - 是的,即使ptr==NULL代码更具可读性,也完全安全地执行!ptr检查空指针。

相关内容

  • 没有找到相关文章