众所周知,C语言一开始只有#define,C程序员用#define定义符号常量。但后来ANSI C加入了const限定符,而const应该比#define更好,为什么现在的C程序员还在大量使用#define来定义常量呢?
这并不是我没有根据地乱说的。这样的例子有很多,例如<limits.h>,例如Windows API,例如OpenGL……
<limits.h>是C标准头文件,发明C语言的人难道不知道const吗?
Windows是Microsoft开发的,难道Microsoft的代码很差劲?
开发OpenGL的难道写的代码也很烂吗?
太奇怪了吧!因此,肯定是有什么特殊原因让他们使用#define……
曾今我在百度上用中文查这个问题,发现根本查不到;昨天我Google了“why use #define instead of const”,才在*上找到了一个同样的问题:
Why do most C developers use define instead of const?
于是我阅读了这个问题的答案,然后挑选出一些答案,翻译出来。下面就是一些回答的原文和翻译(稍有修改),包括回答者的名字我也列出来了~
1. Bart van Ingen Schenau的回答
There is a very solid reason for this: const in C does not mean something is constant. It just means a variable is read-only.
In places where the compiler requires a true constant (such as for array sizes for non-VLA arrays), using a const variable, such as fieldWidth is just not possible.
这有个很可靠的原因:const在C中不表示一个变量是常量。const只表示一个变量是只读的。
在编译器需要一个真正的常量的情况下(例如不可变长数组的大小),使用const变量,例如fieldWidth是不可能的。
2. Vovanium回答
They're different.
const is just a qualifier, which says that a variable cannot be changed at runtime. But all other features of the variable persist: it has allocated storage, and this storage may be addressed. So code does not just treat it as a literal, but refers to the variable by accessing the specified memory location (except if it is static const, then it can be optimized away), and loading its value at runtime. And as a const variable has allocated storage, if you add it to a header and include it in several C sources, you'll get a "multiple symbol definition" linkage error unless you mark it as extern. And in this case the compiler can't optimize code against its actual value (unless global optimization is on).
#define simply substitutes a name with its value. Furthermore, a #define'd constant may be used in the preprocessor: you can use it with #ifdef to do conditional compilation based on its value, or use the stringizing operator # to get a string with its value. And as the compiler knows its value at compile time it may optimize code based on that value.
For example:
#define SCALE 1 ... scaled_x = x * SCALE;
When SCALE is defined as 1 the compiler can eliminate the multiplication as it knows that x * 1 == x, but if SCALE is an (extern) const, it will need to generate code to fetch the value and perform the multiplication because the value will not be known until the linking stage. (extern is needed to use the constant from several source files.)
A closer equivalent to using #define is using enumerations:
enum dummy_enum { constant_value = 10010 };
But this is restricted to integer values and doesn't have advantages of #define, so it is not widely used.
const is useful when you need to import a constant value from some library where it was compiled in. Or if it is used with pointers. Or if it is an array of constant values accessed through a variable index value. Otherwise, const has no advantages over #define.
它们不一样。
const只是个限定符,表示一个变量不能在运行时间被修改。但其他所有属于变量的特性仍保留着:它有已分配的存储器(原文是allocated storage),而且这个存储器可能有地址。所以代码不将它(const变量)看作常量,而通过访问指定的内存位置指代该变量(除非是static const,这样它就会被优化),然后再运行时间加载它的值。然后因为const变量有已分配的存储器,如果你将它加入一个头文件然后在多个C源代码文件中包含它,你会得到一个“符号重定义”的链接错误,除非你将它标记为extern。而且在这种情况下,编译器不能针对其真实值优化代码(除非打开全局优化)。
#define简单地用一个值替代一个名字。此外,一个#define定义的常量可以在预处理器中使用:你可以将其和#ifdef一起使用,在它的值的基础上做条件编译,或者使用连接符#以获取一个值对应的字符串。并且因为编译器在编译时知道它的值,编译器将可以在该值的基础上进行优化。
举个例子:
#define SCALE 1 ... scaled_x = x * SCALE;
当SCALE被定义为1时,编译器可以直接去掉这个乘法运算,因为它知道x * 1 == x。但如果SCALE是一个(extern)const变量,编译器就会需要生成代码以获取其值,然后进行乘法运算,因为SCALE的值在链接阶段以前都是未知的(在多个源代码文件中使用该const变量时需要extern)。
另一个更接近于#define的方法是枚举量:
enum dummy_enum { constant_value = 10010 };
但枚举量被限制为整数,与#define相比没有优势,因此使用不广泛。
在需要从库中导入常量值时const很有用;或者其和指针一起使用;或者其为一个通过索引值访问的常量数组。否则,const对于#define没有优势。
3. R..的回答
The reason is that most of the time, you want a constant, not a const-qualified variable. The two are not remotely the same in the C language. For example, variables are not valid as part of initializers for static-storage-duration objects, as non-vla array dimensions (for example the size of an array in a structure, or any array pre-C99).
原因是因为在大多数情况下,你想要一个常量,而不是有const限定符的变量。两者在C中不完全一样(原文是note remotely the same,不知道有没有犯错)。例如,变量作为静态存储周期对象的initializer的一部分是非法的,例如不可变长数组的大小(例如结构中一个数组的大小,或者C99前的任何数组)。
翻译了一部分,也不知道有没有错误,如果有错误请指出~
看了3个回答,我想答案已经十分明显了。
C中的const和C++的不同。在C中,const定义的常量和#define定义的常量不完全相同。#define是预处理器指令,在编译前就会把所有#define定义的常量的名字全部替换为其值。const定义的常量等同于只读变量,值在链接时才会知道。(我想,我之所以会有这个问题,是因为我直接学了C++而不是先学C,而C和C++中的const不一样。)
因此const定义的常量对于编译器就不是100%的常量,数组长度不能是const常量,只能是#define定义的常量。条件编译的时候也只能使用#define定义的常量。
那么也不是每个常量都是表示数组大小的吧,剩下的常量为什么也是用#define定义的呢?以我naive的思维,估计是因为为了代码风格上的统一吧。
那么在C++中为什么还有很多#define呢?那估计就是继承了C的习惯吧,或者为了兼容C吧……不过,如果是C++,建议使用const,而不是#define,来定义常量。
本文可转载,转载请注明出处:http://www.cnblogs.com/collectionne/p/6713651.html。