说到宏,恐怕大家都能说出点东西来:一种预处理,没有分号(真的吗?)。然后呢?嗯.......茫然中......好吧,我们就从这开始说起。
最常见的宏恐怕是#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++里面的宏的更多相关文章

  1. QVariant(相当于是Java里面的Object,起到一个数据类型“擦除”的作用,可以使用Q_DECLARE_METATYPE进行注册)

    =QVariant= [%这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是 ...

  2. QVariant(相当于是Java里面的Object,是万能的容器,但要注册)

    这个类型相当于是Java里面的Object,它把绝大多数Qt提供的数据类型都封装起来,起到一个数据类型“擦除”的作用.比如我们的 table单元格可以是string,也可以是int,也可以是一个颜色值 ...

  3. Activity往另外一个Activity传值,Fragment获取另外一个Activity里面的值。

    在oneActivity中实现跳转到MainActivity //intent 用来跳转另外一个MainActivity,bundle传值到MainActivity         Intent Ma ...

  4. Java基本概念(2)J2EE里面的2是什么意思

    J2EE里面的2是什么意思 J2SE,J2SE,J2ME中2的含义要追溯要1998年.1998年Java 1.2版本发布,1999年发布Java 1.2的标准版,企业版,微型版三个版本,为了区分这三个 ...

  5. 在wex5平台grid里面的gridselect下拉不能显示汉字问题

    当grid里面有gridSelect组件的时候,gridSelect里面的bind-ref是对应的数据库存入字段(int类型),bind-labelRef是对应的计算字段(视图里面的),而option ...

  6. dede文章调用时过滤调 body里面的style属性和值

    dede 发布文章的时候会在里面的标签中添加一些style 属性,现在改网站想去掉这些属性和里面的值,因为文章太多所以就用下面的方法 \include\arc.listview.class.php 在 ...

  7. 提取数据库字段里面的值,并改变+图片懒加载,jquery延迟加载

    要求:手机端打开某个页面的详细信息,因为网速或者别的原因,响应太慢,因为图片大的原因,希望先进来,图片在网页运行的情况再慢慢加载(jquer延迟加载) http://www.w3cways.com/1 ...

  8. JAVA里面的IO流(一)分类2(节点流和处理流及构造方法概要)

    IO流根据处理对象的不同分为节点流和处理流. 直接对文件进行处理的流为节点流: 对流进行包装从而实现对文件的优化处理的流为处理流. 节点流类型: 可以看出,节点流主要分这几大类: 文件流 文件流构造方 ...

  9. 头文件里面的ifndef /define/endif的作用

    c,c++里面,头文件里面的ifndef /define/endif的作用 今天和宿舍同学讨论一个小程序,发现有点地方不大懂······ 是关于头文件里面的一些地方: 例如:要编写头文件test.h ...

随机推荐

  1. linux开启mysql远程登录

    Mysql默认root用户只能本地访问,不能远程连接管理mysql数据库,Linux如何开启mysql远程连接?设置步骤如下:1.GRANT命令创建远程连接mysql授权用户itloggermysql ...

  2. Linux系统编程(16)——正则表达式入门

    字符是计算机软件处理文字时最基本的单位,可能是字母,数字,标点符号,空格,换行符,汉字等等.字符串是0个或更多个字符的序列.文本也就是文字,字符串.说某个字符串匹配某个正则表达式,通常是指这个字符串里 ...

  3. poj 1001 求高精度幂

    本题的测试用例十分刁钻,必须要考虑到很多的细节问题,在这里给出一组测试用例及运行结果: 95.123 12 548815620517731830194541.899025343415715973535 ...

  4. 网易云课堂_C++开发入门到精通_章节6:多态

    课时33示例--为多态基类声明虚析构函数 微软校园招聘笔试题 #include <iostream> class Base { public: char Value() { return ...

  5. 为什么学微信小程序开发

    微信小程序是什么? 触手可得,不用安装,不体验过自己是想不到的 ---张小龙 小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜 一下即可打开应用.也体现了“用 ...

  6. ffmpeg API录制rtsp视频流

    原文出自http://blog.csdn.net/zxwangyun/article/details/8190638#reply   作者 Sloan 这里在录制时,并没有进行转码,只是相当于把rts ...

  7. C++类构造函数

    一.概述 类是一种用户自定义的类型,声明一个类对象时,编译程序要为对象分配存储空间,进行必要的初始化.在C++中,这项工作是由构造函数来完成的. 大部分对象在使用之前没有正确的初始化是C++出错的主要 ...

  8. C/C++中经常使用的字符串处理函数和内存字符串函数

    一.            字符处理函数 1.        字符处理函数:<ctype.h> int isdigit(int ch) ;//是否为数字,即ch是否是0-9中的字符 int ...

  9. Serializable在C#中的作用——.net中的对象序列化

    序列化是指将对象实例的状态存储到存储媒体的过程,在此过程中,先将对象的公共字段和私有字段以及类的名称(包括类所在的程序集)转换为字节流,然后再把字节流写入数据流,在随后对对象进行反序列化时,将创建出与 ...

  10. NPOI兼容 excel2003,2007版本

    根据项目需要,需要对excel进行导入导出,所以选择NPOI,优点在这里就不详细介绍了,下面进入正题. public int Import(string path) { IList<Studen ...