浅析 C++里面的宏
说到宏,恐怕大家都能说出点东西来:一种预处理,没有分号(真的吗?)。然后呢?嗯.......茫然中......好吧,我们就从这开始说起。
最常见的宏恐怕是#include 了,其次就是#define 还有.......。还是从宏的用途分类吧:
1、#include 主要用于包含引用文件,至今其地位无人能替代;
2、注释掉代码。例如:
#if 0 ....... #endif;
这种机制是目前注释掉代码的最佳选择,为摩托罗拉公司员工所普遍采用;
3、代码版本管理。例如:
#ifdef DEBUG file://调试版本 #else file://非调试版本 #endif;
4、声明宏。例如:
#define DECLARE_MESSAGE(x) x();~x() file://有没有分号?哈哈
//........
class A
{
public:
DECLARE_MESSAGE(A);
..............
}
想起什么了,呵呵:)对,VC 里面有好多这样的东东,有空我会写《我的VC 历程》,到时候会把 VC 里的各种宏详细的解释一下,那可是一个庞大的工程:)
5、符号常量。例如:
#define PI 3.14159
6、内联函数。例如:
#define CLEAR(x) ((x)=0)
7、泛型函数。例如:
#define ABS(x) ((x)>0? (x):-(x))
x=3 没问题! x=1.3 也没问题!
如果是这样呢:
#include <iostream.h>
#define A(x) ((x)>0? (x):-(x))
void main()
{
;
cout<<A()<<endl;
cout<<A(++i)<<endl;
}
有问题了,不过以后再说,大概讲const or inline 时会说的:)
8、泛型类型。例如:
#define Stack(T) Stack__ ##T
#define Stackdeclare(T) class Stack(T) {.....}
Stackdeclare(int);
Stackdeclare(char);
.......
Stack(int) s1;
Stack(char) s2;
9、语法扩展。例如:
Set<int> s;//假设Set 为一个描述集合的类
int i;
FORALL(i,s);
.......
宏最大的问题便是易引起冲突,例如:
libA.h:
#define MACRO stuff
同时:
libB.h:
#define MACRO stuff
下面我们对他们进行引用:
user.cpp:
#include "libA.h"
#include "libB.h"
.............
糟糕,出现了重定义!
还有一种冲突的可能:
libB.h:(没有定义宏MACRO)
class x { void MACRO(); ...........};
那么程序运行期间,libA.h 中的宏讲会改变libB.h 中的成员函数的名字,导致不可预料的结果。
宏的另一个问题,便是如7 中出现的问题,如果你把7 中的x 设为'a',程序也不会给出任何警告,所以他是不安全的。
针对以上的问题,我们说:
1、尽可能的少用公用宏,能替换掉就替换掉;
2、对那些不能替换的宏,使用命名约定;
1、符号常量预处理程序我们可以用const or enum 来代替:
const int TABLESIZE=1024;
enum { TABLESIZE=1024 };
2、非泛型内联函数的预处理程序可以使用真正的内联函数来代替:
inline void clear(int& x) {x=0;}
奥,对了,还有这样一种情况:
#define CONTROL(c) ((c)-64)
..........
switch(c)
{
case CONTROL('a') : ......
case CONTROL('b') : ......
case CONTROL('c') : ......
case CONTROL('d') : ......
..........
}
这时候就不能单独使用内联函数来取代了,因为case 标签禁止函数调用,我们只好做如下转换:
inline char control(char c) { return c+64; }
...........
switch(control(c))
{
case 'a':.....
case 'b':.....
case 'c':.....
case 'd':.....
........
}
当然这样做是以牺牲时间作为代价的(你想想为什么:))
3、对于泛型预处理程序,我们可以用函数模板或类默板来代替:
template<class T>
T ABS(const T& t) { return t>0 ? t : -t; }
template<class T>
Class Stack { ............ };
4、最后对于语法扩展程序几乎都可以用一个或多个C++类代替:
Set<int> s;
int i;
Set_iter<int> iter(s);
while(iter.next(i))
...........
与使用宏相比,我们只是牺牲了一点程序的简洁性而已。
当然并不是所有的宏都能替换(我们也并不主张替换掉所有的宏!),对于不能替换的宏,我们应该对他们实行命名约定,例如:
#define COMPANY_XYZ_LIBABC_MACRO stuff
同时我们也要采取一定的方法,进行预防:
#ifndef COMPANY_XYZ_LIBABC_MACRO
#define COMPANY_XYZ_LIBABC_MACRO stuff
#endif
当然,在程序库实现内部定义的宏没有这个约束:
my.cpp:
#define MACRO stuff
........
我们给出几个常见的宏:
#define A(x) T_##x
#define Bx) #@x
#define Cx) #x
我们假设:x=1,则有:
A(1)=======T_1
B(1)======'1'
C(1)======"1"
还有一个比较常见的宏:_T
TCHAR tStr[] = _T("t code");
_T 宏的作用就是转换成TCHAR
浅析 C++里面的宏的更多相关文章
- QVariant(相当于是Java里面的Object,起到一个数据类型“擦除”的作用,可以使用Q_DECLARE_METATYPE进行注册)
=QVariant= [%这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是 ...
- QVariant(相当于是Java里面的Object,是万能的容器,但要注册)
这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是int,也可以是一个颜色值 ...
- Activity往另外一个Activity传值,Fragment获取另外一个Activity里面的值。
在oneActivity中实现跳转到MainActivity //intent 用来跳转另外一个MainActivity,bundle传值到MainActivity Intent Ma ...
- Java基本概念(2)J2EE里面的2是什么意思
J2EE里面的2是什么意思 J2SE,J2SE,J2ME中2的含义要追溯要1998年.1998年Java 1.2版本发布,1999年发布Java 1.2的标准版,企业版,微型版三个版本,为了区分这三个 ...
- 在wex5平台grid里面的gridselect下拉不能显示汉字问题
当grid里面有gridSelect组件的时候,gridSelect里面的bind-ref是对应的数据库存入字段(int类型),bind-labelRef是对应的计算字段(视图里面的),而option ...
- dede文章调用时过滤调 body里面的style属性和值
dede 发布文章的时候会在里面的标签中添加一些style 属性,现在改网站想去掉这些属性和里面的值,因为文章太多所以就用下面的方法 \include\arc.listview.class.php 在 ...
- 提取数据库字段里面的值,并改变+图片懒加载,jquery延迟加载
要求:手机端打开某个页面的详细信息,因为网速或者别的原因,响应太慢,因为图片大的原因,希望先进来,图片在网页运行的情况再慢慢加载(jquer延迟加载) http://www.w3cways.com/1 ...
- JAVA里面的IO流(一)分类2(节点流和处理流及构造方法概要)
IO流根据处理对象的不同分为节点流和处理流. 直接对文件进行处理的流为节点流: 对流进行包装从而实现对文件的优化处理的流为处理流. 节点流类型: 可以看出,节点流主要分这几大类: 文件流 文件流构造方 ...
- 头文件里面的ifndef /define/endif的作用
c,c++里面,头文件里面的ifndef /define/endif的作用 今天和宿舍同学讨论一个小程序,发现有点地方不大懂······ 是关于头文件里面的一些地方: 例如:要编写头文件test.h ...
随机推荐
- information_schema.column_privileges 学习
mysql 的授权是分层次的 实例级 | 库级 | 表级 | 列级 而这些授权信息被保存在了mysql.user | mysql.db | mysql.tables_priv | mysql.colu ...
- H.264 RTP 封包格式
H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NALU 头由一个字节组成, 它的语法如下: +---------------+ |0|1|2|3|4|5|6|7 ...
- 如何提升app开发效率
无论在什么行业,用户永远都是不可替代的“上帝”,一切的服务,开发都得按照用户的意愿来进行.然而在app开发领域中,专业的技术操作却并不像逛街淘货一样清晰可见,更多的需要app开发人员一行行代码敲出来, ...
- code 代码分析 及其解决方案
官网地址:http://msdn.microsoft.com/zh-cn/library/ms182135.aspx [FxCop.设计规则]11. 不应该使用默认参数 参考地址:http://blo ...
- 什么是优先级队列(priority queue)?
有时候我们需要在某个元素集合中找到最小值和最大值 .优先级队列抽象数据(Priority Queue ADT)模型是我们能够使用的方法之一,这是一种支持插入和删除最小值(DeleteMin)或者最大值 ...
- [置顶] 教你如何搭建RobotFramework环境
看到这篇文章的朋友,相信已经知道RobotFramework是干什么的了,我这里就不再赘述了. 搭建步骤: 1. 下载安装Python,下载地址http://www.python.org/getit/ ...
- Struts2 学习笔记 10 Result部分 part1
1.关于Result我们首先来学习一下结果类型 result type. 先来看struts.xml. struts.xml <?xml version="1.0" enco ...
- Eclipse选中变量名,相同变量都变色显示
Eclipse选中变量名,相同变量都变色显示 java文件的设置"Window"-"preferences"-"Java"-"Ed ...
- IOS 排序算法
/** * @brief 冒泡排序法 * * @param arr 需要排序的数组 */ -(void)BubbleSort:(NSMutableArray *)arr { // 取第一个与其邻接的对 ...
- 使用jqMobi开发app基础:弹出内容的设计
设计APP,因为屏幕非常小.在PC网页山能够放在一体的内容.在APP中就不能放在一起了. 比如例如以下.项目出勤人员非常多,须要弹出一个panel.然后让用户选择,怎样设计呢? 项目出勤panel的内 ...