§1.5 Magic Numbers
[...] This excerpt from a program to print a histogram of letter frequencies on a 24 by 80 cursor-addressed terminal is needlessly opaque because of a host of magic numbers:
...
fac = lim / 20;
if (fac < 1)
fac = 1;
for (i = 0, col = 0; i < 27; i++, j++) {
col += 3;
k = 21 - (let[i] / fac);
star = (let[i] == 0) ? ' ' : '*';
for (j = k; j < 22; j++)
draw(j, col, star);
}
draw(23, 2, ' ');
for (i = 'A'; i <= 'Z'; i++)
printf("%c ", i);
The code includes, among others, the numbers 20, 21, 22, 23, and 27. They're clearly related...or are they? In fact, there are only three numbers critical to this program: 24, the number of rows on the screen; 80, the number of columns; and 26, the number of letters in the alphabet. But none of these appears in the code, which makes the numbers that do even more magical.
By giving names to the principal numbers in the calculation, we can make the code easier to follow. We discover, for instance, that the number 3 comes from (80 - 1)/26 and that let should have 26 entries, not 27 (an off-by-one error perhaps caused by 1-indexed screen coordinates). Making a couple of other simplifications, this is the result:
enum {
MINROW = 1,
MINCOL = 1,
MAXROW = 24,
MAXCOL = 80,
LABELROW = 1,
NLET = 26,
HEIGHT = (MAXROW - 4),
WIDTH = (MAXCOL - 1)/NLET
};
...
fac = (lim + HEIGHT - 1) / HEIGHT;
if (fac < 1)
fac = 1;
for (i = 0; i < NLET; i++) {
if (let[i] == 0)
continue;
for (j = HEIGHT - let[i]/fac; j < HEIGHT; j++)
draw(j+1 + LABELROW, (i+1)*WIDTH, '*');
}
draw(MAXROW-1, MINCOL+1, ' ');
for (i = 'A'; i <= 'Z'; i++)
printf("%c ", i);
Now it's clearer what the main loop does; it's an idiomatic loop from 0 to NLET, indicating that the loop is over the elements of the data. Also the calls to draw
are easier to understand because words like MAXROW and MINCOL remind us of the order of arguments. Most important, it's now feasible to adapt the program to another size of display or different data. The numbers are demystified and so is the code.
#define foo 3
的意思是在你的代码中,任何出现foo
的地方都会被替换成3
。然后编译器会处理这个预处理过的代码。因此,它比 Java 中的final
更加强制,因为编译器实际上并没有看到一个符号,而只是看到了一个值。 - Bill Lynchconst
在 C 语言中应该能够在大多数编译器中正常工作。我认为它最早是在 C89 中添加的,并且也包含在 C99 和 C11 中,这些版本是大多数主要的 C 编译器所实现的。http://en.wikipedia.org/wiki/ANSI_C#Compilers_supporting_ANSI_C - David Winieckiconst
并不意味着完全相同的含义。在C语言中,你不能使用const int
来指定静态数组的维度 - 这将会创建一个可变长度的数组...等等。 - Antti Haapala -- Слава Україніconst
修饰符意味着该值不会改变。但您正确指出,在C中,const int
变量不是常量表达式。为什么会这样,我无法理解。(相比之下,在C++中它是一个常量表达式。)我将更新我的答案以反映这一点。 - Ted Hopp