今天看啥
热点:

宏的使用,使用


前言

宏在C/C++中有挺大的作用。

关键词

 

宏的几种作用

1,定义常量

2,定义表达式

3,简化繁琐的代码

4,作为标识符

5,可变参数

6,#和##的使用

 

1,定义常量

比如定义PI的值可以通过宏来定义

#define PI    3.1415927

2,定义表达式

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

3,简化繁琐的代码

这个可以简化一些重复的代码,比如声明函数,定义类的成员变量,或者是简化多次编写重复性高的代码。

简化函数声明,在函数声明的时候有些必要的关键字需要写,但是很多时候都是一样的,可以通过宏来简化

定义线程函数

unsigned __stdcall ThreadFunc(void* pArguments)

可以通过宏简化为

#define THREAD_FUNC(func)    unsigned __stdcall func(void* pArguments)

THREAD_FUNC(ThreadFunc)
{
    printf("hello\n");
    return 0;
}

 

定义类的成员变量,可能需要定义成员变量的get,set函数,这时候可以通过宏来简化这个过程。

#define PROP_DECL(ClassName, Prop)    \
    public: ClassName Get##Prop(void){return m_##Prop;}\
    public: void Set##Prop(ClassName vl){m_##Prop = vl;}\
    private: ClassName m_##Prop;

class CTestObj
{
    PROP_DECL(int, Count)
public:
    CTestObj();
    ~CTestObj();
};

上面的代码经过预编译之后就会产生GetCount和SetCount两个函数和m_Count私有成员变量。

简化繁琐代码,在内存释放的时候可能需要把指针,需要两行代码

WA *pa = new WA(c);
delete pa;
pa = NULL;

可以使用宏来简化这个过程

#define MEM_FREE(x)    do \
{\
    delete x;\
    x = NULL;\
} while (0)

WA *pa = new WA(c);
MEM_FREE(pa);

在ATL,MFC中大量使用到宏来简化代码。

4,作为标识

作为标识的宏在大量的使用

#ifndef __TMP_H__    //判断是否已经定义宏,如果没有,将会执行下面代码,用于避免包含文件的时候重复包含
#define __TMP_H__    //定义宏,这样第二次包含这个头文件的时候就不会执行下面的定义

//判断是否是UNICODE,用于定义TTCHAR的字符类型。
#ifdef UNICODE        
typedef wchar_t TTCHAR;
#else
typedef char TTCHAR;
#endif

//用于标识的宏定义
#define    IN
#define OUT

#endif // !__TMP_H__

 

4,可变参数

宏可以有参数,而且参数数量可以不定

#define LOG(format, ...)    printf(format, __VA_ARGS__)

LOG("hello, %d, %s\n", 10, "nihao");

5,#和##的使用

#的作用是把宏参数变成字符串

#define STR(s)     #s
printf(STR(hello));           // 输出字符串"hello"

##的作用是把宏参数粘贴起来例子可以参考一下第三点的代码。

 

使用宏需要注意的点

宏是在预处理过程中进行存文本替换,预处理过程中不会对宏进行任何的语法检测,却个括号,少个分号都不会管,所以可能会出现一些很奇怪的错误,所以要慎用。

1,算法优先问题

一个乘法的宏

#define MUL(x, y)    (x * y)

MUL(2,3)的时候没有问题,如果是MUL(1+2, 3)的时候就出事了,宏会替换成1+2*3,跟预想的结果就不一样了。

这时候就需要把宏定义改成

#define MUL(x, y) (x) * (y)

2,分号吞噬问题

#define SKIP_SPACES(p, limit)  \
     { char *lim = (limit);         \
       while (p < lim) {            \
         if (*p++ != ' ') {         \
           p--; break; }}}

如果上面的代码放在判断语句中使用

if (*p != 0)
   SKIP_SPACES (p, lim);
else ...

编译器会报错,else之前要有if,可以通过下面代码来解决

#define SKIP_SPACES(p, limit)     \
     do { char *lim = (limit);         \
          while (p < lim) {            \
            if (*p++ != ' ') {         \
              p--; break; }}}          \
     while (0)

这种方式在linux中大量使用到

 

3,重复调用

#define min(X, Y)  ((X) < (Y) ? (X) : (Y))

如果调用时这样

int x = 1;
int y = 2;
min(x++, y);

展开后x++会被调用两次,这种方式要避免。

 

4,对自身的递归引用

有如下宏定义:

#define foo (4 + foo)

按前面的理解,(4 + foo)会展开成(4 + (4 + foo),然后一直展开下去,直至内存耗尽。但是,预处理器采取的策略是只展开一次。也就是说,foo只会展开成(4 + foo),而展开之后foo的含义就要根据上下文来确定了。

对于以下的交叉引用,宏体也只会展开一次。

#define x (4 + y)
#define y (2 * x)

x展开成(4 + y) -> (4 + (2 * x)),y展开成(2 * x) -> (2 * (4 + y))。

注意,这是极不推荐的写法,程序可读性极差。

 

5,宏参数预处理

宏参数中若包含另外的宏,那么宏参数在被代入到宏体之前会做一次完全的展开,除非宏体中含有#或##。

有如下宏定义:

#define AFTERX(x) X_ ## x
#define XAFTERX(x) AFTERX(x)
#define TABLESIZE 1024
#define BUFSIZE TABLESIZE

AFTERX(BUFSIZE)会被展开成X_BUFSIZE。因为宏体中含有##,宏参数直接代入宏体。
XAFTERX(BUFSIZE)会被展开成X_1024。因为XAFTERX(x)的宏体是AFTERX(x),并没有#或##,所以BUFSIZE在代入前会被完全展开成1024,然后才代入宏体,变成X_1024。

 

宏实在预处理过程中被替换掉的,所以在实际的编译过程中,不会出现宏,或者宏的变量名。

 

参考:

http://hbprotoss.github.io/posts/cyu-yan-hong-de-te-shu-yong-fa-he-ji-ge-keng.html

www.bkjia.comtruehttp://www.bkjia.com/cjjc/1005215.htmlTechArticle宏的使用,使用 前言 宏在C/C++中有挺大的作用。 关键词 宏的几种作用 1,定义常量 2,定义表达式 3,简化繁琐的代码 4,作为标识符 5,可...

相关文章

相关搜索: excel

帮客评论

视觉看点