提问者:小点点

每个空指针常量都是空指针吗?


从C17草案(6.3.2.3¶3):

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

67)NULL中定义

由此可见,以下是空指针常量:00UL(void*)0(void*)0ULNULL

进一步得出以下是空指针:(int*)0(int*)0UL(int*)(void*)0(int*)(void*)0UL(int*)NULL。有趣的是,这些都不是“空指针常量”;见这里。

以下空指针常量是空指针(因为void*是指针类型,00UL是空指针常量):(void*)0(void*)0UL。在这方面,根据C17草案(6.2.5¶19-20):

void类型包含一组空值;它是一个不完整的对象类型,无法完成。
[…]
指针类型可以从函数类型或对象类型派生,称为引用类型。[…]指针类型是一个完整的对象类型。

void本身不是指针类型,它是一个不完整的对象类型。但是void*是一种指针类型。

但似乎以下是空指针常量,它们不是空指针(因为没有对指针类型的强制转换):00ULNULL。(准确地说,虽然标准只要求将NULL定义为“空指针常量”,但允许将其定义为空指针常量,它也是空指针。但似乎标准不要求NULL以同时是空指针的方式定义。)

每个空指针常量都是空指针吗?(NULL真的不是空指针吗?)

最后(有点开玩笑):如果某些空指针常量不是空指针,它们在技术上是一种“非空指针”吗?(这种措辞出现在标准的某些地方。)请注意,从语言上讲,我们有一个所谓的括号悖论;我们可以将其理解为“[非空]指针”或“非[空指针]”。


共3个答案

匿名用户

每个空指针常量都是空指针吗?

太长别读。

正如您已经观察到的,值为0的整数常量表达式是空指针常量,尽管没有指针类型。您还引用了规范对空指针的定义:“转换为指针类型的空指针常量[]”。这意味着这种一般形式的空指针常量…

(void *)(<integer constant expression with value 0>)

…满足“空指针”的定义。整数常量表达式本身就是空指针常量,因此强制转换使整体表达式成为空指针(除了是空指针常量之外)。

另一方面,采用值为0的整数常量表达式形式的空指针常量不满足“空指针”的定义,语言规范中没有其他条款会使它们成为空指针。例如:00x00UL1 2 3-6

该标准似乎不需要以这样一种方式定义NULL,即它同时是一个空指针。

正确。

每个空指针常量都是空指针吗?

当然不是(见上文),但对于大多数目的来说,这并不重要。

NULL真的不是空指针吗?)

这取决于您的C实现。语言规范允许任一答案。实际上,在您可能遇到的大多数实现中,它是一个空指针。

如果某些空指针常量不是空指针,它们在技术上会是一种“非空指针”吗?

不。不是空指针的空指针常量根本不是指针。它们是整数。

匿名用户

每个空指针常量都是空指针吗?

不,原因在你引用的文本中:

如果将空指针常量转换为指针类型,则保证生成的指针(称为空指针)与指向任何对象或函数的指针进行比较不相等。

空指针常量不会自动成为指针,就像任何整数常量不会自动成为指针一样。常量值必须转换为指针类型才能产生空指针。

生成的空指针不必是零值。它只需要是一个不能是任何对象或函数地址的值。该值可以是0x00000000(在我熟悉的实现中),也可以是0xFFFFFFFF,或者它可以是0xDEADBEEF,或者它可以是其他东西。

匿名用户

空指针常量可以是void*或某种整数类型。

在您的机器上测试:

#include <stdio.h>
#include <stdlib.h>

#define NULL_TEST(n) _Generic((n), \
  void *: "void *", \
  int: "int", \
  long: "long", \
  default: "something else" \
)

int main(void) {
  printf("%s\n", NULL_TEST(NULL));
  printf("%s\n", NULL_TEST((void*)0));
  printf("%s\n", NULL_TEST(0));
  printf("%s\n", NULL_TEST(0L));
}

在我的机器上,我有以下输出。您的输出可能会因第一行而异。

void *
void *
int
long