c语言定义常量为什么不建议用#define

如题所述

1、尽量用const和inline而不用#define
这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。
2、再看下面的语句:
#define ASPECT_RATIO 1.653
编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样所写的符号名不会出现在符号列表中。
解决这个问题的方案很简单:不用预处理宏,定义一个常量:
const double ASPECT_RATIO = 1.653;
这种方法很有效。但有两个特殊情况要注意。
首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,要写两次const:
const char * const authorName = "Scott Meyers ";
温馨提示:内容为网友见解,仅供参考
第1个回答  推荐于2017-09-07
条款1:尽量用const和inline而不用#define
这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。再看下面的语句:

#define ASPECT_RATIO 1.653

编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符号列表中。
解决这个问题的方案很简单:不用预处理宏,定义一个常量:

const double ASPECT_RATIO = 1.653;

这种方法很有效。但有两个特殊情况要注意。
首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,你要写两次const:

const char * const authorName = "Scott Meyers ";

关于const的含义和用法,特别是和指针相关联的问题,参见条款21。

另外,定义某个类(class)的常量一般也很方便,只有一点点不同。要把常量限制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要把它定义为静态成员:

class GamePlayer {
private:
static const int NUM_TURNS = 5; // constant eclaration
int scores[NUM_TURNS]; // use of constant
...
};

还有一点,正如你看到的,上面的语句是NUM_TURNS的声明,而不是定义,所以你还必须在类的实现代码文件中定义类的静态成员:

const int GamePlayer::NUM_TURNS; // mandatory definition;
// goes in class impl.file

你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。

旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初始值是非法的;而且,类内只允许初始化整数类型(如:int, bool, char 等),还只能是常量。
在上面的语法不能使用的情况下,可以在定义时赋初值:

class EngineeringConstants { // this goes in the class
private: // header file
static const double FUDGE_FACTOR;
...
};
// this goes in the class implementation file
const double EngineeringConstants::FUDGE_FACTOR = 1.35;

大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个类的常量的情况,例如上面GamePlayer::scores数组的声明(编译过程中编译器一定要知道数组的大小)。所以,为了弥补那些(不正确地)禁止类内进行整型类常量初始化的编译器的不足,可以采用称之为“借用enum”的方法来解决。这种技术很好地利用了当需要int类型时可以使用枚举类型的原则,所以GamePlayer也可以象这样来定义:

class GamePlayer {
private:
enum { NUM_TURNS = 5 } // "the enum hack " — makes
// NUM_TURNS a symbolic name
// for 5
int scores[NUM_TURNS];// fine
};

除非你正在用老的编译器(即写于1995年之前),你不必借用enum。当然,知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是不常见的哟。

回到预处理的话题上来。另一个普遍的#define指令的用法是用它来实现那些看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大值:

#define max(a,b) ((a) > (b) ? (a) : (b))

这个语句有很多缺陷,光想想都让人头疼,甚至比在高峰时间到高速公路去开车还让人痛苦。
无论什么时候你写了象这样的宏,你必须记住在写宏体时对每个参数都要加上括号;否则,别人调用你的宏时如果用了表达式就会造成很大的麻烦。但是即使你象这样做了,还会有象下面这样奇怪的事发生:

int a = 5, b = 0;
max(++a, b);// a 的值增加了2次
max(++a, b+10); // a 的值只增加了1次

这种情况下,max内部发生些什么取决于它比较的是什么值!
幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,再加上可预计的行为和类型安全,这就是内联函数(见条款33):

inline int max(int a, int b) { return a > b ? a : b; }
不过这和上面的宏不大一样,因为这个版本的max只能处理int类型。但模板可以很轻巧地解决这个问题:

template <class T>
inline const T& max(const T& a, const T& b)
{ return a > b ? a : b; }

这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行比较然后返回较大的(常量)对象的引用。因为不知道T的类型,返回时传递引用可以提高效率(见条款22)。

顺便说一句,在你打算用模板写象max这样有用的通用函数时,先检查一下标准库(见条款49),看看他们是不是已经存在。比如说上面说的max,你会惊喜地发现你可以后人乘凉:max是C++标准库的一部分。
有了const和inline,你对预处理的需要减少了,但也不能完全没有它。抛弃#include的日子还很远,#ifdef/#ifndef在控制编译的过程中还扮演重要角色。预处理还不能退休,但你一定要计划给它经常放长假。

参考资料:http://wenwen.soso.com/z/q255708081.htm?pid=ask.box

本回答被提问者采纳
第2个回答  2011-10-12
这个,看常量类型,如果程序中大量使用且以后可能要经常改变这个常量的值,还是用#define比较方便,否则的话就没有必要了!
第3个回答  2013-07-04
C语言的常量就是使用#define定义的。你是说C++吧?C++的常量推荐使用const 定义,因为#define只是单纯的字符替换,无法检查数据类型,const定义常量需指明数据类型,利于编译器进行类型检查。
第4个回答  2011-10-12
1、那是因为对于#define定义,编译器会存放在一个记忆区域,这个记忆区域相当于我们称为宏
为了不把有需要的装进这个区域,我们只把有必要的,特殊的放进去
2、当用#deifne定义的量是不能更改的,这样就没法循环使用了。

c语言定义常量为什么不建议用#define
1、尽量用const和inline而不用#define 这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。2、再看下面的语句:define ASPECT_RATIO 1.653 编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程...

c语言编程 为什么关键字define,include...前面能加#
这些不叫做关键字, 关键字绝不能带#的 这些是预处理命令, 或者叫做宏, 不是C语言的主体. 是编译器进行预处理时执行的 一般是用来定义常量的 预处理命令都以#开头 常用的有 define include ifdef

C语言中的#define与typedef有和区别;static与extern定义有和区别?
从以上的概念便也能基本清楚,typedef只是为了增加可读性而为标识符另起的新名称(仅仅只是个别名),而#define原本在C中是为了定义常量 ,到了C++,const、enum、inline的出现使它也渐渐成为了起别名的工具。有时很容易搞不清楚与typedef两者到底该用哪个好,如#define INT int这样的语句,用typedef一样...

define在c语言中是什么意思
一、明确答案 在C语言中,"define"通常用于定义常量或者宏。使用预处理指令"#define"可以在编译阶段定义常量或宏,这些定义在编译时会被替换到代码中。二、详细解释 1. 预处理指令与宏定义:在C语言中,编译器在进行正式的编译过程之前会进行一个预处理阶段。在这个阶段,编译器会处理一些特殊的指令,...

C语言中怎样定义常量变量
常量的定义用const关键字:const 类型名 常量名=值;变量的定义是:类型名 变量名;

PHP 为什么不鼓励使用 define 定义全局常量
define容易产生意想不到的错误,有时可能并不希望在任何地方都替换。const显然对字符串等地方就不会有效果

C语言中的#define是什么意思,有什么作用,怎样用??
define 定义一个标识符来表示一个常量。其特点是定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了。用 #define 定义标识符的一般形式为:define 标识符 常量 \/\/注意, 最后没有分号 define 和 #include 一样,也是以“#”开头的。凡是以“#”开头的均为预处理指令,#...

#define的用法不解
第二种是定义常数,如#define max 100,则max代表100(这种情况下使用const定义常数更好,因为:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误 );第三种是定义"函数",如#defin...

c语言define用法举例
在C语言中,`#define`是一个预处理指令,用于创建宏(macros)。宏是一种用于简化代码的工具,通常用于在编译时替换为一段代码或表达式。 以下是一些`#define`用法和例子的说明:1. **常量定义**:这是最常见的使用场景。你可以使用`#define`来定义一个常量,比如:```c #define PI 3.14159 ``...

C语言中#define是什么意思
在C语言编程中,#define是一个关键的预处理命令,它的主要作用是提升代码的可维护性和灵活性。通过定义宏,程序员可以为程序中的常量或复杂的表达式创建一个简短的名称,便于在代码中多次使用和修改。想象一下,如果你正在处理一个大型项目,其中包含数千行代码,且某个常量如N占据了大部分篇幅。如果没...

相似回答