浅析 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 ...
随机推荐
- .net 拉姆达 groupby(p => p.X) order by count(c.Count())
//国家 var entityCountriesList = aliexpressEntities.SYS_CourierCode.Where(whereSelect.Compile()).Group ...
- information_schema.collation_character_set_applicability 学习
字符集和排序规则之间是不可以随便搭配的.如果你想知道一个字符集它所搭配的排序规则有哪些?那就可以从information_schema.collation_character_set_applicab ...
- 关于MySql链接url参数的设置
jdbc.driverClassName=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/database?useUnicode=t ...
- java设计模式--行为型模式--状态模式
什么是行为型模式,小编觉得就是对行为的一种描述啦,一种对某种行为模型的定义. 状态模式: 状态模式 概述 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被 ...
- UESTC_韩爷的梦 2015 UESTC Training for Search Algorithm & String<Problem N>
N - 韩爷的梦 Time Limit: 200/100MS (Java/Others) Memory Limit: 1300/1300KB (Java/Others) Submit Stat ...
- Capture the Flag(模拟)
Capture the Flag Time Limit: 2 Seconds Memory Limit: 65536 KB Special Judge In computer se ...
- .net网站开发(设计):1.什么是MVC模式
好吧我知道,应该很少人一开始学网站开发就从MVC开始,但如果你已经理解了三层架构之类的,那直接尝试强大的微软MVC网站开发模式也是挺不错的. 但其实我们学校有个实验室,那些干进去的就算是大一的学生,也 ...
- Oracle SQL函数之转换函数
chartorowid(c1) [功能]转换varchar2类型为rowid值 [参数]c1,字符串,长度为18的字符串,字符串必须符合rowid格式 [返回]返回rowid值 [示例] SQL> ...
- Linux Tomcat7.0安装配置实践总结
一,安装JDk 先下载jdk,链接http://www.oracle.com/technetwork/java/javase/downloads/index.html,选择相对应平台的JDK.由于笔者 ...
- android 获取屏幕尺寸
文章转载自:http://blog.csdn.net/congqingbin/article/details/7474276// 通过WindowManager获取 DisplayMetrics dm ...