宝塔服务器面板,一键全能部署及管理,送你10850元礼包,点我领取

编程中的[魔数](magic number)是什么意思-编程部落

一、魔数的来源

在源代码编写中,有这么一种情况:编码者在写源代码的时候,使用了一个数字,比如0x2123,0.021f等,他当时是明白这个数字的意思的,但是别的程序员看他的代码,可能很难理解,甚至,过了一段时间,代码的作者自己再看代码的时候也忘记了这个数字代表的含义。于是感叹,虽然不知道这个数字是干什么用的,究竟代表什么,但是编译后的程序可以正常运行,真是“魔术般的数字”,魔数即源于此。

二、魔数的用法

“魔数”有贬义词、中性词、褒义词三种用法,默认为贬义词。

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 );

配合前后的代码,这句代码可以快速计算一个数字的平方根的倒数。具体推导过程比较复杂,涉及到浮点数的原理。

3、中性词“魔数”

某些具有特定格式的文件,喜欢在文件开头写几个特殊的字符以表明自己的身份,以便验明正身。例如常见的几种图片格式的文件:

JPEG (jpg),文件头:FFD8FF

PNG (png),文件头:89504E47

GIF (gif),文件头:47494638

Windows Bitmap (bmp),文件头:424D

如果你用16进制编辑器打开一个文件,它的开头不是FFD8FF,那就不是jpg文件。这个魔数一般会在相关文件标准中进行规定,所有人都要遵守。

三、魔数的弊端

1、代码可读性差

例如float time=1.0f;//小数类型时间=1.0f

float speed=time*2.13f;//小数类型速度=时间*2.13f

如果没有说明,很难猜到那个2.13f的含义,假如它代表加速度,那么修改如下:

#define ACCELERATION (2.13f);/*#定义加速(2.13f)前等于后*/

float speed=time*ACCELERATION;//小数类型速度=时间*加速

这样对于代码阅读者来说更好理解。

2、修改不方便

例如setfontcolor(string,0xFFFFFFFF);/*设置字体颜色(字符串,0xffffffff);设此函数设置一个字符串的颜色*//*等等……*/

setbackcolor(widget,0xFFFFFFFF);/*设置背景色(小部件,0xffffffff);设此函数设置控件背景色*//*等等……*/暂且不说0xFFFFFFFF代表的含义,如果程序中很多地方使用了统一的一个常量,如果要修改值的时候很麻烦,也容易出错。可能有遗漏等等诸多问题。

同样可以改为如下:

static const int WHITE=0xFFFFFFFF;/*静态常量整数类型WHITE=0xFFFFFFFF;WHITE是白色*/

setfontcolor(string,WHITE);/*设置字体颜色(字符串、WHITE);*//*等等……*/

setbackcolor(widget,WHITE);//设置背景色(小部件、WHITE);/*等等……*/

这样程序代码不仅便于阅读,而且要替换他的值,只需要替换一次就好了。

解决魔术数字的方法主要是将这些数字定义为常量,或者枚举类型,或者使用编译器的宏定义(如C/C++的#define)