我一直在思考空指针

Lobsters Hottest 新闻

摘要

作者探讨了空指针的概念,讨论了其语义角色,并提出可以像NaN装箱那样,使用其他无效指针值来存储额外信息。

<p><a href="https://lobste.rs/s/tnlxmc/i_ve_been_thinking_about_null_pointers">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/15 13:44

# 我一直在想空指针的问题 来源:https://sebsite.pw/w/20260715-null.html null 很奇怪。你思考过空指针吗?因为我一直在想空指针的问题。 明确一下,当我说“null 很奇怪”时,我指的不是安全性。如果你使用一个设计合理的编程语言,空安全问题几乎就不存在了。不,我的意思是,整个 null 的概念都有点奇怪。 比方说,你有一个指针类型。它指向某个东西。它包含所指向东西的地址。 但是这里有一个(1)值,它**不是**一个地址;它是一种传达一段语义信息的方式。 而这条信息取决于上下文:在 C 语言中通常用来表示发生了错误,或者在各种语言中你可以用它来表示某个可能存在的东西不存在。有时它传达的是完全不同的信息,比如,向一个函数传入 null 以告诉它分配自己的指针,而不是使用用户提供的指针。而这一切都只通过一个值来传达。 这就引出了关于 null 的另一个奇怪之处。大多数语言中指针类型的概念是,一个指针可能具有**任何**值,除了一个值——也就是空指针。但其他任何值都可以。特别是在 C 语言中,空指针几乎被规定为它自己的东西,其语义与任何其他指针完全不同。 问题是,在用户空间中,并非每个指针值都是可能的地址。至少在 Linux 上,64 位指针只使用 48 位,所以所有高于 `1 << 47` 的值都是无效的。我还假设有很多低值永远不可能有效。所以,假设一个用户空间指针永远不会低于 0x1000 的地址。 那么就有**大量**不同的非地址值可以被指针存储!如果我们已经在用 null 存储语义信息,为什么不继续扩展呢? 我以 Hare 标准库中的一个函数为例,因为 Hare 是我熟悉的语言,它能说明我想表达的观点,但明确一下,这并非针对 Hare 的语言提案;只是一个思想实验,也许可以为其他更具实验性的编程语言提供一个思路: `bufio::scan_line` 的返回类型是 `(str | io::EOF | io::error | utf8::invalid)`,这是一个标记联合(tagged union)。所以返回类型既包含一个标记,也包含一个指针(包含在 `str` 中)。但指针只在标记为特定值时有效。而所有其他可能返回的类型都是 `void` 的别名(除了 `io::error`,它本身是 `void` 别名的标记联合,但这里不影响)。 所以空指针被用来表示空字符串,这个函数可能会返回它。但我们也可以将 `io::EOF` 表示为一个值为 `0x1` 的“指针”。并且我们可以将各种 `io::error` 类型表示为其他永远不会指向真实对象的指针值。这样一来标记就完全不需要了,返回类型现在可以放进两个 64 位寄存器(指针 + 长度)中。 这只是一个例子。这个想法有点像 NaN boxing,只不过是用指针代替浮点数,而且限制更多一些。基本上,null 已经作为一种在指针类型中存储其他值的方式存在,而 null 没有理由比任何其他不可能地址更特殊,那么为什么不直接添加更多值呢? 不知道,这只是一个思想实验,可能是个糟糕的主意,null 很奇怪。

相似文章

Go 中过度的空指针检查

Lobsters Hottest

一篇博客文章讨论了 Go 中过度的空指针检查如何可能表明代码不清晰和错误处理实践不佳,主张早期失败并显式建模不可用的依赖。

关于NaN的两个案例分析

Lobsters Hottest

本文探讨了NaN在Python和Lua中的两种意外行为,其中对相等性和比较的隐含假设导致了令人惊讶的结果,例如Python列表相等性忽略了NaN的自不等性,以及Lua的for循环将NaN作为步长或限制时处理不当。

关于C数组类型语义的讨论

Lobsters Hottest

本文解释了C数组类型的令人困惑的行为,包括它们退化为指针、sizeof和函数参数等例外情况,并将其与函数类型进行比较,提出了一种数组和指针严格分离的心理模型。

C字符串:一个50年的错误

Lobsters Hottest

对C语言中空终止字符串的批评,认为基于长度的字符串在现代编程中更优越,可以减少错误并提高性能。