当空指针不是所有位为零时,如何正确编写C/C++代码

iva*_*ult 69 c c++ computer-architecture

正如comp.lang.c常见问题所述,有一些架构,其中空指针不是所有位零.所以问题是实际检查以下结构:

void* p = get_some_pointer();
if (!p)
    return;
Run Code Online (Sandbox Code Playgroud)

我是否p与机器相关的空指针进行比较或者我是否p与算术零进行比较?

我应该写

void* p = get_some_pointer();
if (NULL == p)
    return;
Run Code Online (Sandbox Code Playgroud)

相反,为这样的架构做好准备还是仅仅是我的偏执?

iva*_*ult 100

根据C规范:

值为0的整型常量表达式或类型为void*的表达式称为空指针常量.55)如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较.

所以0是一个空指针常量.如果我们将它转​​换为指针类型,我们将得到一个空指针,对于某些体系结构可能是非全零位零.接下来让我们看看规范中有关比较指针和空指针常量的内容:

如果一个操作数是指针而另一个是空指针常量,则空指针常量将转换为指针的类型.

让我们考虑(p == 0):首先0将其转换为空指针,然后p与空指针常量进行比较,该指针常量的实际位值取决于体系结构.

接下来,看看规范中关于否定运算符的内容:

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

这意味着(!p)相当于(p == 0)根据规范测试p机器定义的空指针常量.

因此,if (!p)即使在空指针常量不是全位为零的体系结构上,您也可以安全地编写.

对于C++,空指针常量定义为:

空指针常量是整数类型的整数常量表达式(5.19)prvalue,其计算结果为零或类型为std :: nullptr_t的prvalue.空指针常量可以转换为指针类型; 结果是该类型的空指针值,并且可以与对象指针或函数指针类型的每个其他值区分开.

这与我们的C语言接近,加上nullptr语法糖.运算符的行为==定义如下:

此外,可以比较指向成员的指针,或指向成员的指针和空指针常量.执行成员转换(4.11)和资格转换(4.4)的指针以使它们成为通用类型.如果一个操作数是空指针常量,则公共类型是另一个操作数的类型.否则,公共类型是指向成员类型的指针,类似于(4.4)与其中一个操作数的类型,具有cv-限定签名(4.4),它是操作数类型的cv限定签名的并集.[注意:这意味着任何指向成员的指针都可以与空指针常量进行比较. - 结束说明]

这导致转换为0指针类型(对于C).对于否定运算符:

逻辑否定运算符的操作数!在上下文中转换为bool(第4条); 如果转换的操作数为true,则其值为true,否则为false.结果的类型是bool.

这意味着结果!p取决于如何bool执行从指针的转换.标准说:

零值,空指针值或空成员指针值转换为false;

所以,if (p==NULL)if (!p)做同样的事情,在C++中了.

  • 恕我直言这是唯一*完整*答案,只要***指出标准定义`!E`与`E == 0`(C11草案6.5.3.3/7)等相同. (7认同)

Yu *_*Hao 32

如果空指针在实际机器中是否为全零位,则无关紧要.假设p是一个指针:

if (!p) 
Run Code Online (Sandbox Code Playgroud)

总是一种合法的方法来测试if p是否为空指针,并且它始终等效于:

if (p == NULL)
Run Code Online (Sandbox Code Playgroud)

您可能对另一篇C-FAQ文章感兴趣:这很奇怪.NULL保证为0,但空指针不是?


以上适用于C和C++.请注意,在C++(11)中,最好使用nullptrnull指针文字.

  • 为什么链接文章中的陈述都不完整?他们都以"......"结束,为什么? (3认同)
  • @MarsonMao因为他们每个都以下一个语句的引入结束. (2认同)

Lun*_*din 10

这个答案适用于C.

不要NULL与空指针混淆.NULL只是一个保证为空指针常量的宏.空指针常量保证为0(void*)0.

从C11 6.3.2.3开始:

值为0的整型常量表达式或类型为void*的表达式称为空指针常量66).如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较.

66)宏NULL在<stddef.h>(和其他头文件)中定义为空指针常量; 见7.19.

7.19:

宏是

空值

它扩展为实现定义的空指针常量;

在以下情况下定义的实现NULL0或者(void*)0.NULL不可能是别的什么.

但是,当一个空指针常量被赋给一个指针时,你得到一个空指针,它可能没有值为零,即使它比较等于空指针常量.代码if (!p)NULL宏无关,您将空指针与算术值零进行比较.

所以从理论上讲,代码int* p = NULL可能会导致一个p与零不同的空指针.

  • 空指针常量可以是评估为"0"的ICE,例如"NULL"可以定义为"(1 - 1)". (2认同)
  • 一元 `!` 运算符的定义使得 `!x` 与 `x == 0` 相同,因为 `x == 0` 对 `NULL` 指针具有预期的效果,`!x` 会检查对于“NULL”指针在数字上不等于 0 的平台上的“NULL”。 (2认同)

Gle*_*aum 7

在当天,STRATUS计算机的所有语言中的空指针都为1.

这导致了C的问题,因此他们的C编译器将允许0和1的指针比较返回true

这将允许:

void * ptr=some_func();
if (!ptr)
{
    return;
}
Run Code Online (Sandbox Code Playgroud)

return在一个空PTR,即使你可以看到,ptr在调试器中有值1

if ((void *)0 == (void *)1)
{
    printf("Welcome to STRATUS\n");
}
Run Code Online (Sandbox Code Playgroud)

事实上会打印"欢迎来到STRATUS"

  • 空指针常量可以有任何表示不是历史性的,也不是单一架构的扩展。这是两种语言的核心事实。毕竟,抽象是这些语言的全部目的。 (2认同)