Effective C++_笔记_条款02_尽量以const、enum、inline替换#define
(整理自Effctive C++,转载请注明。整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/)
这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#define不被视为语言的一部分,那正是它的问题所在。#define命令是C语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。#define的基本用法有两种,都容易出现问题,C++也分别采用不同的方法进行解决。
1. 简单的宏定义
1.1 核心内容
1: #define PI 3.14
记号名称PI也许从未被编译器看见,在编译器处理源码之前就被预处理器移走了。即记号名称PI根本就没进入记号表内。当你运用此常量但获得一个编译错误时,可能会带来困惑,因为这个错误信息也许会提到3.14而不是PI,当这个宏被定义在非你所写的头文件中,你肯定对3.14以及它来自何处毫无概念。
怎么解决这个问题呢?以一个常量替换上述的宏(#define)就可以了:
1: const double Pi = 3.14 //大写名称通常用于宏,这里用改变名称写法
作为一个语言常量,Pi肯定会被编译器看到,当然就会就会进入到记号表内。
用常量替换#define,有两种特殊情况。
(1)定义常量指针。由于常量定义式通常被放在头文件内,因此有必要将指针声明为const。
(2)class内的专属常量。为了将常量的作用域限制于class内,必须让它成为class的一个成员;而为确保此常量至多只有一份实体,必须让它成为一个static成员。
1.2 概念补充
为了能够真正理解#define的作用,让我们来了解一下对C语言源程序的处理过程。C++程序从源代码到可执行的二进制文件经历了预处理、编译、汇编和连接几个过程。其中预处理器产生编译器的输入,它实现以下的功能: 
(1)文件包含
可以把源程序中的#include 扩展为文件正文,即把包含的.h文件找到并展开到#include 所在处。
  
(2)条件编译
预处理器根据#ifdef和#ifndef等编译命令及其后的条件,将源程序中的某部分包含进来或排除在外,通常把排除在外的语句转换成空行。
  
(3)宏展开
预处理器将源程序文件中出现的对宏的引用展开成相应的宏 定义,即本文所说的#define的功能,由预处理器来完成。
经过预处理器处理的源程序与之前的源程序有所有不同,在这个阶段所进行的工作只是纯粹的替换与展开,没有任何计算功能,所以在学习#define命令时只要能真正理解这一点,这样才不会对此命令引起误解并误用。
2. 带参数的宏定义
1: #define N 2+2
2: void main()
   3: {
4: int a=N*N;
5: cout << a << endl ;
6: }
在此程序中存在着宏定义,宏N代表的字符串是2+2,在程序中有对宏N的使用,一般同学在读该程序时,容易产生的问题是先求解N为2+2=4,然后在程序中计算a时使用乘法,即N*N=4*4=16。但其实结果为8,原来宏展开是在预处理阶段完成的,这个阶段把替换文本只是看作一个字符串,并不会有任何的计算发生,在展开时是在宏N出现的地方 只是简单地使用串2+2来代替N,并不会增添任何的符号,所以对该程序展开后的结果是a=2+2*2+2,计算后=8。若要计算结果为16:
1: #define N (2+2)
你以为加上括号,问题就能得到圆满解决?在原书上举了一个更加极端的例子:下面这个宏夹着带宏实参,调用函数f,
1: #define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))
2: int a = 5 , b = 0 ;
3: CALL_WITH_MAX(++a,b);//a被累加一次
4: CALL_WITH_MAX(++a,b+10);//a被累加两次
1: template<typename T>
2: inline void callWithMax(const T& a , const T& b)
   3: {
4: f(a > b ? a : b) ;
5: }
Effective C++_笔记_条款02_尽量以const、enum、inline替换#define的更多相关文章
- 读书笔记_Effective_C++_条款二:尽量以const, enum, inline替换#define
		
其实这个条款分成两部分介绍会比较好,第一部分是用const和enum替换不带参的宏,第二部分是用inline替换带参的宏. 第一部分:用const和enum替换不带参宏 宏定义#define发生在预编 ...
 - Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define
		
尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...
 - NO.2: 尽量以const,enum,inline 替换 #define
		
1.首先#define 定义不重视作用域(scope),虽然可以#undef控制,但是不美观,还存在多次替换的问题,以及没有任何封装性. 2.const XXX_XX,保证其常量性以及可控的作用域,如 ...
 - Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define
		
1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...
 - Effective C++ -----条款02:尽量以const, enum, inline替换 #define
		
class GamePlayer{private: static const int NumTurns = 5; int scores[NumTurns]; ...}; 万一你的编译器(错误地)不允许 ...
 - Effective C++之条款2:尽量以const enum inline替换 #define
		
本文的标题也可以改成“用编译器替换预处理器”: const double AspectRatio = 1.653; //最好使用上述代码替换下述代码: #define ASPECT_RATIO 1.6 ...
 - 条款2:尽量以const, enum, inline替换#define
		
原因: 1. 追踪困难,由于在编译期已经替换,在记号表中没有. 2. 由于编译期多处替换,可能导致目标代码体积稍大. 3. define没有作用域,如在类中定义一个常量不行. 做法: 可以用const ...
 - 条款2:尽量使用const ,enum,inline替换define
		
宁可使用编译器而不用预处理器 假设我们使用预处理器: #define ABC 1.56 这标识符ABC也许编译器没看到,也许它在编译器处理源码前就被预处理器移走了,于是“标识符”ABC没有进入标识符列 ...
 - 条款02:尽量以const,enum,inline替换#define
		
目录 1. 总结 2. 使用const常量或enum替换宏常量 class外部的常量指针 class专属常量 1. 总结 对于单纯常量,最好以const常量或enum替换#define 对于宏代码段, ...
 - Book. Effective C++ item2-尽量使用const, enum, inline替换#define
		
##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...
 
随机推荐
- Android中弹出对话框,AlertDialog关键代码
			
写在这里便于以后查看. Android中弹出对话框的关键代码: btn01.setOnClickListener(new OnClickListener() { @Override public vo ...
 - 我的Python成长之路---第四天---Python基础(14)---2016年1月23日(寒风刺骨)
			
一.生成器和迭代器 1.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退. ...
 - php 登陆动作详解
			
<?php class LoginAction extends Action { function index(){ $this->display(); } function do_log ...
 - 基于visual Studio2013解决C语言竞赛题之0604二维数组置换
			
 题目
 - 基于visual Studio2013解决C语言竞赛题之0518回文数
			
 题目
 - 全栈project师的悲与欢
			
从小米辞职出来创业的两个多月里,通过猎头或自己投简历,先后面试了知乎,今日头条,豌豆荚,美团,百度,App Annie,去哪儿,滴滴打车等技术团队,一二面(技术面)差点儿都轻松的过了,三面却没有毕业那 ...
 - ant_0105
			
在projectA中执行projectB的构件文件.projectA的构件文件内容如下 <?xml version="1.0"?> <!-- 在projectA中 ...
 - 高级UIKit-02(文件操作)
			
[day3_1_Sandbox]:沙箱的介绍 snadbox沙箱沙盒 沙箱根目录下的几个文件夹: 1.应用名称.app存放应用程序的素材 2.Documents:存放应用运行时需要用到的数据(关键性数 ...
 - 2个NASM开发环境下载以及30篇教程(lostspeed)
			
http://download.csdn.net/detail/lostspeed/8958175http://download.csdn.net/detail/lostspeed/8954263 h ...
 - cocos2d-x游戏开发系列教程-中国象棋05-开始游戏
			
前情回顾 通过CCMainMenu的init函数,已经把所有的按钮,棋子都摆放完毕了,但是这个时候,棋子是不能走动的,只有在开始游戏之后才能移动棋子. 点击