C/C++宏定义学习(持续更新,05/11)

宏定义的使用建议

1)虽然宏定义很灵活,并且通过彼此结合可以产生许多变形用法,但是 C++/C 程序员不要定义很复杂的宏,宏定义应该简单而清晰。

2)宏名采用大写字符组成的单词或其缩写序列,并在各单词之间使用“_”分隔。

3)如果需要公布某个宏,那么该宏定义应当放置在头文件中,否则放置在实现文件(.cpp)的顶部。

4)不要使用宏来定义新类型名,应该使用 typedef,否则容易造成错误。

5)给宏添加注释时请使用块注释(/* */),而不要使用行注释。因为有些编译器可能会把宏后面的行注释理解为宏体的一部分。

6)尽量使用 const 取代宏来定义符号常量。

7)对于较长的使用频率较高的重复代码片段,建议使用函数或模板而不要使用带参数的宏定义;而对于较短的重复代码片段,可以使用带参数的宏定义,这不仅是出于类型安全的考虑,而且也是优化与折衷的体现。

8)尽量避免在局部范围内(如函数内、类型定义内等)定义宏,除非它只在该局部范围内使用,否则会损害程序的清晰性。

1.宏定义#与##的区别和使用

  • 定义
#define f(a,b) a##b      //     (1)
#define g(a)   #a        //     (2) 
#define h(a)   g(a)      //     (3)  
  • 使用情况
printf("%s\n", g(f(1, 2)));
printf("%s\n", h(f(1, 2)));

输出以下结果:
f(1, 2)
12
  • 解释
1)符号#表示“字符串化”的意思,就是把跟在后面的参数转换成一个字符串,
例如上述代码中g(f(1, 2))输出的结果为f(1, 2)
2)符号##是一个连接符号,用于把参数连在一起,例如a##b等同于ab
  • 注意点
1)如果宏定义是带#的,如上所示,则直接替换:g(f(1,2))等于#f ( 1 , 2 ),也就是“ f (1 , 2) ”
2)如果宏定义是不带#的,如h(f(1, 2 ) ) 所示,基本原则为展开参数然后替换。也就是h(12),也就是 "12"
  • 总体步骤

步骤为:由外层向里层走,如果碰到的是以非#开头的宏,则继续往里层走,直到最里层,然后开始往外层展开。如果碰到的是以#开头的宏,则不再往里层走,往外层展开。h(f(1,2))—>h(12)—>g(12)—>#12—>“12”

  • 代码举例
char a = 'c';
cout << g(a) << endl; // "a"
cout << g(g(a)) << endl; // "g(a)"
printf("%s\n", h(f(1, 2)));   // "12"
printf("%s\n", g(f(1, 2))); // "f(1,2)"
printf("%s\n", g(h(f(1, 2)))); // "h(f(1,2))"
printf("%s\n", h(g(f(1, 2)))); // ""f(1,2)""
printf("%s\n", h(h(f(1, 2)))); // ""12""

2.算数组的大小

//定义
#ifndef ARR_LEN
#define ARR_LEN(a)  (sizeof(a) / sizeof(*(a)))
#endif

#ifndef DIM
#define DIM(arrar_name) (sizeof(arrar_name) / sizeof(arrar_name[0]))
#endif


//使用
int targets_len = ARR_LEN(_targets);	//这个_targets是数组的大小

3.宏定义比较大小

//取小
template<class T=int>
const T& tmin(const T&a , const T&b)
{
	return (a>b)?b:a;
}

//取大
template<class T = int>
const T& tmax(const T&a , const T&b)
{
	return (a<b)?b:a;
}

4.算术符优先问题

#define COUNT(M) M*M
int x=5;
print(COUNT(x+1));
print(COUNT(++X));
//结果输出:11   和42 而不是函数的输出36
  • 注意:

1)预编译器只是进行简单的文本替换,COUNT(x+1)被替换成 COUNT(x+1x+1),5+15+1=11,而不是 36

2)CUNT(++x)被替换成++x*++x 即为 67=42,而不是想要的 66=36,连续前置自加加两次

5、容器遍历

// vector 的循环简化处理
#define FOREACH_VECTOR(_array, _condition, _do) for (size_t i=0 ; i < _array.size(); i++){	if (_condition){_do;} }
// 例子: FOREACH_VECTOR(m_vtMembers, m_vtMembers[i]->m_hActorID == hActorID, return m_vtMembers[i]);
#define FOREACH_IN_CONTAINTER(itNAME, CONTAINER) for(auto itNAME = (CONTAINER).begin(); itNAME != (CONTAINER).end(); ++itNAME )
#define FOREACH_IN_CONTAINTER_C(itNAME, CONTAINER) for(auto itNAME = (CONTAINER).cbegin(); itNAME != (CONTAINER).cend(); ++itNAME )
#define FOREACH_IN_CONTAINTER_R(itNAME, CONTAINER) for(auto itNAME = (CONTAINER).rbegin(); itNAME != (CONTAINER).rend(); ++itNAME )

6、判断空字符串

//   判断是否为空字符串
#ifndef IS_STR_EMPTY
#define IS_STR_EMPTY(x) ((x)[0]=='\0')
#endif

7、复制字符串

//   复制字符串
#ifndef MY_STRNCPY
#define MY_STRNCPY(dst, src, maxlen) strncpy((dst), (src), (maxlen)-1);(dst)[(maxlen)-1]='\0';
#endif

8、导出dll的函数

#if (defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64))

#ifndef DLL_EXPORT
#define DLL_EXPORT  __declspec(dllexport)
#endif
  • 使用例子
DLL_EXPORT void myFunction() {
    // function implementation
}

This will tell the compiler to export the myFunction function from the DLL. Other modules that link to the DLL will then be able to access this function.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值