为什么很多人使用#define而不是const定义常量
众所周知,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”,才在stackoverflow上找到了一个同样的问题:
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 =
};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 =
};
但枚举量被限制为整数,与#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。
为什么很多人使用#define而不是const定义常量的更多相关文章
- PHP中define()和const定义常量的区别
在PHP中可以通过define()和const两种方式定义常量可是在开发中我们应该什么时候用define()定义常量,什么时候用const定义常量? 这两种方式定义常量的主要区别是什么? 从5.3版本 ...
- 在php中define和const定义常量的区别
define和const都可以用来定义常量,但是const定义常量的时候大小写敏感,而define可以通过设置第三个参数为true的时候来取消大小写敏感! 如图: 引用地址:点这里
- C++ —— 非类中使用const定义常量的初始化,以及#define和typedef的区别
总结一下在非类中使用const关键字定义常量时的初始化问题,亲测VS2015.顺便记录#define宏和typedef的区别. 1 首先对const声明的常量的初始化做简单小结: , w2 = , w ...
- PHP 中 define() 和 const 定义常量时的区别
自 PHP 5.3.0 起,有两种方式定义常量,使用 const 关键字或者 define() 函数: 1 2 const FOO = 'BAR'; define('FOO', 'BAR'); 这 ...
- iOS define 宏定义 和 const定义常量区别
const const 是c++中的修饰符. c++中常用来定义常量,修饰左值. #define 宏定义语句, 在预处理阶段直接做文本替换,不做类型检查. 它们之间的最大区别: 1. 对于co ...
- php中const定义常量
const 常量 1.在定义时必须被初始值,2.前面不加任何修饰符3.变量名字母一般都大写4.常量可以被子类继承5.一个常量是属于一个类的,而不是某个对象的 作用:当某些值是固定不变的,就用const ...
- C中const 定义常量的使用
先看如下代码 #include <stdio.h> #include <string.h> #define ARRSIZE(a) (sizeof(a)/sizeof(a[0]) ...
- #define宏与const的区别
1.#define宏的用法 #define用宏名代替一个字符串,这样便于修改,提高了程序的可移植性.编译器在编译预处理时只对宏做文本替换,而不进行类型检查,所以替换后可能产生一些副作用. 带参数的宏类 ...
- const define 定义常量的区别
1.用const定义常量在编译的时候,提供了类型安全检查,而define 只是简单地进行字符串的替换 2.const定义的常量,会分配相应的内存空间.而define没有分配空间,只是在程序中与处理的时 ...
随机推荐
- mysql性能优化配置总结
看了一些优化mysql运维的一些书籍,在此记录总结下:进入mysql客户端输入以下sql:1.连接设置 show variables like '%max_connection%'; show sta ...
- Html 经典布局(二)
经典布局案例(二): <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- 如何选择合适的PHP开发框架
PHP作为一门成熟的WEB应用开发语言,已经深受广大开发者的青睐.与此同时,各式各样的PHP开发框架也从出不穷,面对如此多而且良莠不齐的开发框架,开发者们想必都会眼花缭乱,不知道该选择用哪个.其实并没 ...
- 树状数组 && 线段树
树状数组 支持单点修改 #include <cstdio> using namespace std; int n, m; ], c[]; int lowbit(int x) { retur ...
- open vswitch常用操作
以下操作都需要root权限运行,在所有命令中br0表示网桥名称,eth0为网卡名称. 添加网桥: #ovs-vsctl add-br br0 列出open vswitch中的所有网桥: #ovs-vs ...
- eharts入门篇一
1.导入文件样式 从官网下载界面选择你需要的版本下载,根据开发者功能和体积上的需求,我们提供了不同打包的下载,如果你在体积上没有要求,可以直接下载完整版本. 2,引入 ECharts 文件 < ...
- 安装node-saas包报错问题
项目中用到一些sass写的样式,但是每次一编译就报错 按照它上面的提醒,npm rebuild node-sass --force,还是一样有错.不过仔细看看他的错误信息我发现了其中这条: gyp v ...
- html自定义调控
为什么需要自定义数据属性? 很多时候我们需要存储一些与不同DOM元素相关联的信息.这些信息对于读者来说可能是不需要的,但是可以轻松的访问这些信息将会给我们开发者的工作带来极大的便利. 例如,假设你有一 ...
- 不完全图解HTTP
在2D平面上行走的时候,认识只局限于“点”,刚认识一个新的点,就把之前的那个点忘记了,捡了芝麻丢西瓜.只从3D视角俯瞰时,把这些点连接在一起,点成线,线成面时,才能有所顿悟.话不多说,这是我对HTTP ...
- Vue2.x中的父组件数据传递至子组件
父组件结构 template <template> <div> <v-girl-group :girls="aGirls"></v-gir ...