“魔数”有贬义词、中性词、褒义词三种用法,默认为贬义词。
1、贬义词“魔数”
指的是代码中出现的没有说明的数字。代码中突然出现一个没说明用途的数字会让其它阅读代码、维护代码的的人非常难受。例如:
const int N = 2073600;
for (int i=0; i<N; i++)
{ ......
看代码的人需要猜2073600是什么意思,而且特别难猜。改成这样就清楚多了:
const int WIDTH = 1920;
const int HEIGHT = 1080;
int totalPixels = WIDTH * HEIGHT;
这里的“魔数”就是指代码中直接出现的数字。现代编程规范比较忌讳这样写代码,一方面看不懂意思,另一方面如果2073600这个数字多次出现,一旦需要修改的时候就需要全部找出来改掉,一旦少改一处就会产生BUG,非常麻烦。
我们在编程中要尽可能避免使用“魔数”,例如写3.1416这种数字,也应该改为数学库中的π常数,例如Unity中的Mathf.PI。
2、褒义词“魔数”
最典型的例子就是现代3D游戏之父约翰·卡马克在雷神之锤中的那个魔数:
i = 0x5f3759df - ( i >> 1 );
配合前后的代码,这句代码可以快速计算一个数字的平方根的倒数。具体推导过程比较复杂,涉及到浮点数的原理。
这个靓丽的骚操作给了其它人非常大的震撼,是那个年代的大神级编程技术的缩影,所以被人们怀着敬仰之情称之为“魔数”,全称为“如魔法一样神奇的数字”。
这其中有:
1. 一些图像文件中存在的魔数。比如,bmp文件中的’BM’,JPEG/JFIF中的’JFIF’,等等。
2. 某些格式的声音、视频文件中存在中的魔数。
3. PE文件、ELF文件中存在的魔数。
4. 各种文本编码中的BOM也可以看做魔数。比如UTF-8、UTF-16、UTF-32的BOM。
……
可以看到,很多文件类型都定义了自己的magic number来刷存在感。
说到魔数,不得不提Linux下的file命令。
file命令是一个很神奇的命令。它能够根据文件中魔数来判断文件类型。这比根据后缀来判断文件类型要靠谱一点。比如,即使把一张位图文件后缀名改为.jpg,file命令依然大公无私地告诉你它是一张bmp图片。
对于文本文件,file能够猜测文件是用什么编码存储的(但是并不总正确。要知道字符编码是一个很复杂的事情。所以,有一次,我在自己一个用Python写的小工具中使用了libmagic + chardet + 人工判断来判断文本文件的编码)。
file命令其实是依赖于libmagic的(C版本:libmagic | SourceForge.net,Python版本:ahupp/python-magic · GitHub),而libmagic则是从一个配套的“魔数数据库”(暂且这么叫吧)magic.mgc中来获取不同文件的标志性魔数,进而实现文件类型的判断。有兴趣的代码猴子可以探究一下magic.mgc文件中有哪些魔数(我没探究过)。
这里给出一些相关链接:
Magic editing and creation: a primer
Linux file utility magic.mgc database get content
此外,Python中附带两个根据文件中魔数来简单地判断一下文件类型的库:
21.8. imghdr
21.9. sndhdr
第一个根据图像文件中的魔数来判断图像文件的格式,第二个则判断声音文件的格式。用IDLE打开这两个库,看一看它们都用了哪些魔数吧。
最后,我想说一下的是,医学影像设备产生的DICOM图像文件中的魔数才多得丧心病狂。发两张以前分析DICOM图像时截的图片吧。