正常
病在哪儿:-1 是个什么都能装的筐
先给你看个场景。你写了个用户程序,调
read(),内核返回-1。然后呢?是文件读到尾了(EOF)?盘 IO 出错了?文件根本不存在?你没权限?——-1把这四件完全不同的事揉成了一个数,你对着日志里一句[SYS_MKDIR] failed干瞪眼,不知道下一步该查哪。这一章治两件越往后越扎手的事。第一,给内核的错误一个名字、一个类型——
ErrorOr,让"出错了"不再是含糊的-1,而是"什么错"。第二,把散在内核各处、东一份西一份的公共类型(StringView、Span、RingBuffer、CRC32…)收进一个共享库Cinux-Base,别再每个子系统自己造一遍。这两件是后面文件系统、多进程、网络那些大特性的地基——地基不夯实,越往上晃得越厉害。
先看清病:-1 是个什么都能装的筐
在只有只读 ext2 + 单进程 shell 的小体量下,"出错返 -1、调用方看着办"勉强够用——出错路径就那么几条,-1 大致等于"没找到 / 读崩了 / 你给错了"三合一。可一旦系统要长大,这套就崩了。三个具体的疼:
三态歧义。 int read(...) 这个返回值,-1 是错、0 是 EOF、正数是字节数。调用方得记着这套不成文的约定,稍不留神就把 EOF 当成错误处理了。
错误信息丢了。 -1 不会告诉你"没找到"还是"盘崩了"还是"权限不够"。排查时日志只剩一句含糊的失败,对着猜。
类型不帮你。 -1 是个 int,编译器没法在你忘了检查错误时提醒你。它就是个普通的返回值,你爱忽略就忽略,忽略了就把一个错误值一路传进文件系统深处,某天炸在一个莫名其妙的地方。
这三疼,根源是同一个:错误没有身份。它只是个约定俗成的数,没有名字、没有类型、没有"非处理不可"的强制性。