[转载]你这 Hello World,有 Bug 啊

gggxbbb 86 2022-03-10

原文地址:https://blog.sunfishcode.online/bugs-in-hello-world/

注意!本文并非严格意义上的翻译作品,用词风格及情感色彩或与原文存在些许出入。为了符合中文用语习惯和中国互联网环境,部分词句表达不会严格按照原文。同时,由于本人并非十分熟悉 C 语言,文中涉及 C 语言一例的翻译或存在难以理解的部分。

Hello World 或许是最常被编写的计算机程序了。几十年来,它都是许多人开始学习一门新的程序语言时编写的第一个程序。

理所当然的,这个毫不起眼的开始应当是没有 Bug 的,对吧?

毕竟,Hello World 就只是输出个 Hello World,又能有什么坏心思 Bug 呢?

看看 C 语言?

在 C 语言中写 Hello World 的方法有许多种。有维基百科版本K&R书中的hello world,甚至还有1974年已知最古老的C hello world程序

这里采用另一个 “ANSI C” 中的版本:

/* Hello World in C, Ansi-style */

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

int main(void)
{
  puts("Hello World!");
  return EXIT_SUCCESS;
}

这是最小心谨慎的一个版本。它使用了 (void) 来确保 main 时新式声明,使用了 EXIT_SUCCESS 而不是 0 来表示成功,这可以规避掉一部分的风险(真没必要),同时它也使用了正确的 headers 来防止隐式声明 puts 。这看起来可以完美地输出“ Hello World! ”。

但是,它存在一个 Bug。

之前提到的其他版本中也存在着这个 Bug。

真有 Bug?

Linux 有个有趣的驱动器文件叫做 “/dev/full”,它跟著名的 “/dev/null” 很像。但不同的是,后者会丢弃所有被写入其中地数据,而前者永远是满的。

$ echo "Hello World!" > /dev/full
bash: echo: write error: No space left on device
$ echo $?
1

这是一个测试程序是否正确处理 I/O 错误的很棒的小工具。你可以把它轻易作为一个满的或坏的磁盘来使用,而不是历经万难去创设一个这样的文件系统。

让我们来试试上面的代码吧!

$ gcc hello.c -o hello
$ ./hello > /dev/full
$ echo $?
0

不像我们之前使用 echo 时那样,我们没有得到输出,并且退出状态是 0,这意味着这个程序回报说它正常运行了!但事实上我们都知道,他失败了。通过使用 strace,我们可以确信它确确实实遇到了异常:

$ strace -etrace=write ./hello > /dev/full
write(1, "Hello World!\n", 13)          = -1 ENOSPC (No space left on device)
+++ exited with 0 +++

看!操作系统说没空间了!但这又和程序有什么关系呢?程序把这个错误瞒了下来,让系统误以为没有发生异常,这是不对的!

这严重吗?当然,在 Hello World 中这算不上什么。但是,在其他需要标准输出的地方,这可能会导致一些问题。特别是当输出到一个文件时,明明失败了系统却不知道,于是乎系统继续向前运行,这或将导致数据的丢失,亦或是系统的错误!一片寂静之中,你的数据少了一半!

比方说你要输出一个 yaml 或其他什么,明明没有空间了却未处理这一异常,你将获得一个无效的 yaml!

必要之时,我们需要把这一 Bug 纳入考虑范围。

那么,其他语言呢?

看看原文吧!

这里贴一张引子原文的表格

语言有这个 Bug?测试版本
CYes(all)
C++Yes(all)
Python 2YesPython 2.7.18
RubyYesruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux-gnu]
JavaYesopenjdk 11.0.11 2021-04-20
Node.jsYesv12.21.0
HaskellYesThe Glorious Glasgow Haskell Compilation System, version 8.8.4
RustNorustc 1.59.0 (9d1b2106e 2022-02-23)
Python 3NoPython 3.9.5
PerlNoperl 5, version 32, subversion 1 (v5.32.1) built for x86_64-linux-gnu-thread-multi (with 46 registered patches...)
Perl 6Nov2020.12
BashNoGNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
AwkNoGNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
OCamlNo4.08.1
TclNo8.6.11
C#NoMono JIT compiler version 6.8.0.105

# 标准输入输出 # 翻译 # 学习