Friday, July 20, 2007

有关程序中的Magic Number

Magic Number有很多意思了,在code里面,主要是指不使用const声明为常量而直接使用在程序里的数值常量,如:
int a[512]; 中的512
应尽量避免在程序中使用Magic Number。

以下转载自answers.com

Magic numbers in code
The term magic number also refers to the bad programming practice of using numbers directly in source code without explanation. In most cases this makes programs harder to read, understand, and maintain. Although most guides make an exception for the numbers zero and one, it is a good idea to define all other numbers in code as named constants.
For example, to shuffle the values in an array randomly, this pseudocode will do the job:

for i from 1 to 52
j := i + randomInt(53 - i) - 1
a.swapEntries(i, j)

where a is an array object, the function randomInt(x) chooses a random integer between 1 to x, inclusive, and swapEntries(i, j) swaps the ith and jth entries in the array. In this example, 52 is a magic number. It is considered better programming style to write:
constant int deckSize := 52
for i from 1 to deckSize
j := i + randomInt(deckSize + 1 - i) - 1
a.swapEntries(i, j)
This is preferable for several reasons:
It is easier to read and understand. A programmer reading the first example might wonder, What does the number 52 mean here? Why 52? The programmer might infer the meaning after reading the code carefully, but it's not obvious. Magic numbers become particularly confusing when the same number is used for different purposes in one section of code.
It is easier to alter the value of the number, as it is not redundantly duplicated. Changing the value of a magic number is error-prone, because the same value is often used several times in different places within a program. Also, if two semantically distinct variables or numbers have the same value they may be accidentally both edited together. To modify the first example to shuffle a Tarot deck, which has 78 cards, a programmer might naively replace every instance of 52 in the program with 78. This would cause two problems. First, it would miss the value 53 on the second line of the example, which would cause the algorithm to fail in a subtle way. Second, it would likely replace the characters 52 everywhere, regardless of whether they refer to the deck size or to something else entirely, which could introduce bugs. By contrast, changing the value of the deckSize variable in the second example would be a simple, one-line change.
The declarations of "magic number" variables are placed together, usually at the top of a function or file, facilitating their review and change.
It facilitates parameterization. For example, to generalize the above example into a procedure that shuffles a deck of any number of cards, it would be sufficient to turn deckSize into a parameter of that procedure. The first example would require several changes, perhaps:
function shuffle (int deckSize)
for i from 1 to deckSize
j := i + randomInt(deckSize + 1 - i) - 1
a.swapEntries(i, j)
It helps detect typos. Using a variable (instead of a literal) takes advantage of a compiler's checking (if any). Accidentally typing "62" instead of "52" would go undetected, whereas typing "dekSize" instead of "deckSize" would result in the compiler's warning that dekSize is undeclared.
It can reduce typing in some IDEs. If an IDE supports code completion, it will fill in most of the variable's name from the first few letters.
Disadvantages are:
It can increase the line length of the source code, forcing lines to be broken up if many constants are used on the same line.
It can make debugging more difficult, especially on systems where the debugger doesn't display the values of constants.

Allowed use of magic numbers
Although somewhat controversial, most programmers would concede that the use of 0 (zero) and 1 are the only two allowable magic numbers in general code. There are several reasons for this.
Some programming languages begin arrays and lists at index 0, while others begin at index 1
A 0-based array requires a count minus one upper index limit in a loop. For example:
for index := 0 to list.count-1 do
DoSomething(index);
0 equates to false and 1 to true in many programming languages. For this reason these two numbers are considered valid Magic Numbers (although most programmers would argue that the explicit constants TRUE and FALSE should be used instead).
Some languages (notably C and [[C++]]) use 0 to indicate a null pointer constant (although many programmers would argue that the explicit constant NULL should be used instead).

Problems with magic numbers
Because magic numbers are of an arbitrary value, they do not often carry a meaning by themselves; in most cases it is up to the documentation of ones code to specify exactly what the magic number represents. Also, magic numbers are not typesafe, that is, one could erroneously add one to another and arrive at a nonsensical result. Lastly, although highly coincidental, situations arise when numbers may accidentally match magic numbers during comparison operations. It is for these reasons that the use of Enumerated types, or enums, is quickly overtaking the use of magic numbers. Although enums are represented in most languages as a glorified integer (a notable exception is Java)[5], the name of the enum is used rather than the number itself, facilitating programming.

No comments:

Post a Comment