防不胜防的编程陷阱
本文最后更新于:2023年7月24日 下午
防不胜防的编程陷阱
这里记录了很多本人在编程过程中偶然碰到的容易被忽视的bugs
文本文件风格
总所周知,忽略兼容性永远是引发bug的第一把好手。很多情况下,我们在一个平台上开发的程序在另一个平台上运行大概率就会出现问题。那么同样,如果是文件风格的不同,也会引发难以察觉的bug。
C程序读取文件
在计算机中,文件分为两大类——二进制文件和文本文件,我们日常能够去编辑的文件都是文本文件(当然某些黑客能够自信地hack二进制文件)。而文本文件主要又分为两种风格——dos风格和unix风格,前者是Windows系统,后者是Unix-like的所有操作系统。如果你使用的是vim编辑器的话,输入以下命令:
:echo &ff " short for fileformat
就能查看当前的文件是什么文件风格的。
要说两种文件风格有什么不同之处,那主要就是行尾控制字符的不同。unix风格是LF(line feed),dos风格是CRLF(carriage return, line feed)。事实上并不是我说的这么简单,详情请看这个问题解答。于是我们有了另一种分辨两种风格的方式,在你的shell中输入file指令(当然你也可以直接在vim中输入):
file Add.asm
如果它显示结果:
Add.asm: ASCII text, with CRLF line terminators
则说明这个文件是dos风格的文件。
由此,一个因文件风格引发的bug就诞生了。如果你在C程序中调用fopen(filepath, "r")
来读入一个文件的话,你就得在处理文件行尾时格外注意一下。如果是unix风格,就直接使用\n
(for newline or linefeed),dos风格就还需要额外使用\r
(for carriage return)来判断一下,因为dos文件的行尾控制符是\r\n
,很多情况下,你要是硬是使用unix格式打开,行尾就会显示为^M
。
解释一下为什么存在CRLF:CR是用来控制文件读取头放置到行首的,而LF是控制跳转到新到一行,早期如果没有CR,跳转到新一行读取头还是会处在相同到列数上
Python file.tell()
你可能注意到了,像是python这样的更为高层级一些的编程语言在设计时就直接为我们解决了不同文件风格造成的烦恼。如果我们使用open()
函数,只要我们读取文件内容,python内置库就会自动帮助我们避开换行符,只会给我们传递有效字符,这一点无疑让我们省去了不少麻烦。但是往往正是如此,我们就会默认忽视文件风格的差异,从而使bug更不容易被发现。比方说这个file.tell()
函数。
这个函数是用来获取文件指针的位置的(整型),但在极端情况下,它会返回一些反常的大数字。如果阅读它的文档就会发现,如果是dos文件格式的文件中出现了unix格式的换行符(也就是只有LR),那么就会造成上述的异常。使用binary mode('rb'
)可以避免这种问题。
说个题外话,当时找这个bug的时候真的苦痛
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!