Lov*_*ure 18 c void-pointers null-pointer language-lawyer
来自 C17 草案 (6.3.2.3 \xc2\xb63):
\n\n\n值为 0 的整型常量表达式,或此类转换为类型的表达式
\nvoid *,称为空指针常量。67)如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与任何对象或函数的指针比较不相等。67)该宏
\nNULL在(和其他标头)中定义<stddef.h>为空指针常量 [...]。
由此可见,以下是空指针常量:0, 0UL, (void *)0, (void *)0UL, NULL。
进一步得出以下是空指针:(int *)0, (int *)0UL, (int *)(void *)0, (int *)(void *)0UL, (int *)NULL。有趣的是,这些都不是“空指针常量”;看这里。
以下空指针常量是空指针(因为void *是指针类型,并且0和0UL是空指针常量):(void *)0, (void *)0UL。对此,根据C17草案(6.2.5\xc2\xb619-20):
\n\n该
\nvoid类型包含一组空值;它是一个不完整的对象类型,无法完成。
\n[...]
\n指针类型可以派生自函数类型或对象类型,称为引用类型。[...] 指针类型是完整的对象类型。
void本身不是指针类型,而且是不完整的对象类型。不过void *是指针类型。
但似乎以下是不是空指针的空指针常量(因为没有转换为指针类型):0, 0UL, NULL。(准确地说,虽然标准只要求NULL定义为“空指针常量”,但定义为空指针常量也是允许的,它也是空指针。但标准似乎并没有规定要求NULL以这样的方式定义它同时是一个空指针。)
每个空指针常量都是空指针吗?(NULL 真的不是空指针吗?)
最后(有点半开玩笑):如果某些空指针常量不是空指针,那么它们在技术上是一种“非空指针”吗?(这个措辞出现在标准中的某些地方。)请注意,从语言学上讲,我们有一个所谓的括号悖论;我们可以将其读作“[非空]指针”或“非[空指针]”。
\nJoh*_*ger 24
每个空指针常量都是空指针吗?
TL;DR:没有。
正如您已经观察到的,值为 0 的整型常量表达式是空指针常量,尽管没有指针类型。您还引用了空指针规范的定义:“将空指针常量[]转换为指针类型”。这意味着这种一般形式的空指针常量......
(void *)(<integer constant expression with value 0>)
Run Code Online (Sandbox Code Playgroud)
...满足“空指针”的定义。整型常量表达式本身就是一个空指针常量,因此强制转换使整个表达式成为空指针(除了作为空指针常量之外)。
另一方面,采用值为 0 的整数常量表达式形式的空指针常量不满足“空指针”的定义,并且语言规范中没有其他规定使它们成为空指针。例子:0,0x00UL,1 + 2 + 3 - 6。
似乎该标准不要求以同时为空指针的方式定义 NULL。
正确的。
每个空指针常量都是空指针吗?
绝对不是(见上文),但对于大多数目的来说,这并不重要。
(
NULL真的不是空指针吗?)
这取决于你的 C 实现。语言规范允许任一答案。实际上,在您可能遇到的大多数实现中它都是空指针。
如果某些空指针常量不是空指针,那么它们在技术上是一种“非空指针”吗?
不。不是空指针的空指针常量根本就不是指针。它们是整数。
Joh*_*ode 10
每个空指针常量都是空指针吗?
不,原因在您引用的文字中:
如果将空指针常量转换为指针类型,则生成的指针(称为空指针)保证与任何对象或函数的指针比较不相等。
空指针常量不会自动成为指针,就像任何整型常量不会自动成为指针一样。必须将常量值转换为指针类型才能生成空指针。
生成的空指针不必为零值。它只需是一个值,不能是任何对象或函数的地址。该值可能是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));
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上,我有以下输出。第一行的输出可能会有所不同。
void *
void *
int
long
Run Code Online (Sandbox Code Playgroud)
不,事实上,没有一个空指针常量是空指针!这是因为常量和指针是不同类型的实体。
\n空指针常量是具有特定形式的常量表达式。表达式是标记序列,空指针常量被定义为具有特定形式的标记序列。
\n空指针是一个值。在 C 中,每种类型都有其一组潜在值。对于每种指针类型,该集合中的一个或多个值是空指针。C 标准没有正式定义值的概念。正式的语义需要做到这一点(并且正式定义指针的值变得相当复杂,这就是为什么 C 标准,一个没有数学编写的英文文档,没有尝试)。
\n表达式计算为上下文中的值(可能会导致副作用)。所有类型为指针类型的空指针常量均计算为空指针。一些空指针常量(例如0,1L - 'z' / 'z')具有整数类型,并且它们不会计算为空指针:它们计算为空整数(即值为 0 \xe2\x80\x94 的整数,C 标准不使用表达式 \xe2\x80\x9cnull 整数\xe2\x80\x9d 因为它不是什么值得注意的需要特定名称的东西)。
C 标准保证,如果e是整数类型且值为 0 的常量表达式,则任何将此值转换为指针类型的表达式都会计算为空指针。请注意,此保证不适用于任意表达式:即使定义为(void*) f(),也可能不是空指针。fint f(void) { return 0; }
C 标准允许NULL使用整数类型或指针类型。如果它具有指针类型,则表达式的NULL计算结果为空指针。如果它有整数类型,则没有。
| 归档时间: |
|
| 查看次数: |
5037 次 |
| 最近记录: |