【C++常识】C++中宏的使用

  C/C++从编辑到生成目标文件的过程中,经历了预处理(#include、#if、#define)、编译、汇编和链接这几个过程,宏替换就是出现在预处理中,宏替换时不做任何的语法检查。由于宏替换时上下文可能存在不同的情况,因此要求对宏替换过程中对存在的变量使用括号包起来,切为了避免歧义,尽量不要在宏中使用自增自减运算符。

一、宏中使用#以及##

说明:“#”将宏中的参数字符串化,“##”将2个token连接为1个

// 输出class的大小
#define OUT_CLASS_SIZE(_Class)  do{\
    cout << #_Class << " size is:" << sizeof(_Class) << endl;}while (0);

// 获取基类的类型
#define GetClassBase(type) C##type##Bass

class CHouseBass{};
class CHouse:public CHouseBass{};
// 以上定义了2个类,CHouse继承于CHouseBass,这里使用GetClassBase宏定义了一个基类的对象
GetClassBase(House)  housebassObj;

三、宏在字符串中的使用

在使用C++调用SQLITE的demon中,将宏替换写入了一个字符串中,但运行的时候与预期不一致。

先看代码:

#define _VAR_ARG_20 (20)
#define _VAR_ARG_40 (40)
#define _VAR_ARG_SPEC   (20-30)

char *str = "Target Pin[_VAR_ARG_20]:Value[_VAR_ARG_40]:Spec[_VAR_ARG_SPEC]";

编译无问题,运行的时候,str中的各个宏并没有被替换。第一反应是,宏是在预编译的时候进行替换的,不应该存在问题才对。后来仔细想想,char *实际上是一个存放在静态存储区里面的字符串,其实质是一个右值,不允许修改,且其创建是在预编译之前完成的,字符串中的宏被视为普通的字符串不会被替换。

如果要实现字符串的替换,可以使用 # 号连接一个字符串与宏。

也可以先使用占位符替换宏,然后以格式化字符的方法使用宏替换占位符达到目的。

二、宏在语言国际化中的使用

//第一版本的语言国际化
// 中文、英文
enum _EN_LANGUAGE{eLanguage_Chinese = 0,eLanguage_English};
_EN_LANGUAGE g_enLanguage = eLanguage_English;
#define defString(no,en,cn) string string_language_no(GetLanguage()?en:cn);
//等价于: string string_language_1101("Welcome To Luran‘s Home \r\n");
defString(1101,"Welcome To Luran‘s Home \r\n","欢迎来到卢然之家\r\n")
#define GETSTRING(no)   string_language_no

//第二版本的语言国际化:对比第一版本是定义一个全局变量,第二版本定义的是一个string的数组,
//且当不知道上次语言设置时,可以使用 eLanguage_Last 来设置继承上次语言设置
enum _EN_LANGUAGE{eLanguage_Chinese = 0,eLanguage_English,eLanguage_Last};
_EN_LANGUAGE g_enLanguage = eLanguage_English;
#define SetLanguage(language)  do {    if(eLanguage_Last != language)        g_enLanguage = language ;}while(0)

#define GetLanguage() g_enLanguage
#define defString(no,en,cn) static string string_id_##no[eLanguage_Last] = {en,cn};
#define GETSTRING(no)   string_id_##no[GetLanguage()]
defString(1101,"Welcome To Luran‘s Home \r\n","欢迎来到卢然之家\r\n")

int main()
{
    SetLanguage(eLanguage_Chinese);
    cout << GETSTRING(1101).c_str() << endl;
    SetLanguage(eLanguage_English);
    cout << GETSTRING(1101).c_str() << endl;
    getchar();
    return 0;
}

四、获类取成员变量的偏移量

#define OFFSET(structure, member) ((int)&((structure*)0)->member);

典型例子是通过某一类的成员变量的地址来获取该类对象的地址,如linux内核中链表的实现。

五、使用do{….}while(0)

使用do{….}while(0) 将需要的代码包裹起来,成为一个独立的语法单元,可以避免多条语句的情况下报错

#define dosomething(x) x++;x*=2;

if(bok)
  dosomething(x);  // dosomething扩展后,由于if和else之间存在多条语句,且无{}包裹,导致便宜错误
else
  dootherthing();

使用do{}while(0)可以很好的消除以上问题

#define dosome(x) do{\
    x++;    x*=2;\
}while(0)

六、进行类型强转

以下代码将指定地址转换为class_ex类型的对象或该对象的指针

#define addr_to_class_ex( p_addr ) ( *( (class_ex*) (p_addr) ) )#define addr_to_class_ex( p_addr ) ( ( (class_ex*) (p_addr) ) )

七、防止溢出

#define INC_VAL( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))

八、返回数组个数

#define ARRAY_NO(arr) ((sizeof(arr)/sizeof(arr[0])))

九、宏调试

_LINE_ /*(两个下划线),对应%d*/
_FILE_ /*对应%s*/
_DATE_ /*对应%s*/
_TIME_ /*对应%s*/
时间: 2024-11-09 18:40:36

【C++常识】C++中宏的使用的相关文章

C++中宏的定义与用法(现已被内联函数所代替)

在noip中,宏还是被经常采用,所以这里讲一下,C++中宏的定义与用法 第一种用法——配合条件编译:#define DEBUG 定义一个叫DEBUG的标识符.它应该与#ifdef或#ifndef配合使用.举例如下: #define DEBUG #ifdef DEBUG void print(int v) { cout << v << endl;} #else void print(int) {} #endif 如果符号DEBUG存在,那么编译器会编译上面的.能输出数值的print,

C语言中宏定义(#define)时do{}while(0)的价值(转)

C语言中宏定义(#define)时do{}while(0)的价值 最近在新公司的代码中发现到处用到do{...}while(0),google了一下,发现Stack Overflow上早有很多讨论,总结了一下讨论,加上自己的理解,do{...}while(0)的价值主要体现在: 1. 增加代码的适应性 下面的宏定义没有使用do{...}while(0) #define FOO(x) foo(x); bar(x); 这样宏定义,单独调用不会出现问题,例如: FOO(100) 宏扩展后变成: 1 f

ATL中宏定义offsetofclass的使用

近日学习ATL,通过对宏定义offsetofclass的解惑过程,顺便分析下虚函数表,以及通过虚函数表调用函数的问题. 1 解开ATL中宏定义offsetofclass的疑惑 #define _ATL_PACKING  8 #define offsetofclass(base, derived) ((unsigned long)(static_cast <base*>((derived*)_ATL_PACKING))-_ATL_PACKING) 分析如下:(base 基类 , derived

ATL中宏定义offsetofclass的分析

近日学习ATL,通过对宏定义offsetofclass的解惑过程.顺便分析下虚函数表,以及通过虚函数表调用函数的问题. 1 解开ATL中宏定义offsetofclass的疑惑 #define _ATL_PACKING  8 #define offsetofclass(base, derived) ((unsigned long)(static_cast <base*>((derived*)_ATL_PACKING))-_ATL_PACKING) 分析例如以下:(base 基类 , derive

C语言中宏的使用(#,##,do…while(0)宏)

1.预定义宏的使用__FILE__,__FUNCTION__,__LINE__. #include <stdio.h> void fun(void) { char v1; short v2; int v3; long v4; printf("v1: %x\n",&v1); printf("v2: %x\n",&v2); printf("v3: %x\n",&v3); printf("v4: %x\n&

zabbix 中 宏 的介绍

宏的作用是便于在模板.items.trigger中的引用.宏的名称为 {$名称},宏的字符范围为 A~Z.0~9._ . 例如: 在key中的宏: net.tcp.service[ssh,{$SSH_PORT}] 其中,{$SSH_PORT}就是一个红,可以在添加items的时候,对不同端口的ssh单独定义端口,这样模板就可以被多个主机引用,达到通用的目的. 作用范围:模板,主机 配置步骤为:单击 administration -> general -> macros .就可以找到宏的定义

编写一个可变参数的C函数——头文件stdarg.h中宏va_start ,va_arg和va_end的应用

我们在C语言编程中会遇到一些参数个数可变的函数,例如printf()这个函数,它的定义是这样的:int printf( const char* format, ...);它除了有一个参数format固定以外,后面跟的参数的个数和类型是可变的,例如我们可以有以下不同的调用方法:printf("%d",i);printf("%s",s);printf("the number is %d ,string is:%s", i, s);究竟如何写可变参数的

C语言中宏定义使用方法详解

C语言中的宏替换详解 首先看一个问题: #include <stdio.h> #define    PRINT_CLINE()    printf("%d", ______) int main(void) { PRINT_CLINE(); PRINT_CLINE(); return 0; } 在横线处填上适当的代码,使得上面这段代码的输出为34. 我想一般人看到这个问题的时候头脑里都没有明确的思路来解答这个它.我看到这个问题的时候想出了各种办法来解答它,最终还是没有通过编译

C语言中宏定义之 ## 用于可变参数

GCC 支持复杂的宏,它使用一种不同的语法,使你可以给可变参数一个名字,如同其它参数一样,比如: 引用 #define debug(format, args...) fprintf(stderr, format, args) 这种定义可读性更强,也更容易描述.完整测试代码: 引用 #include <stdio.h> #define debug(format, args...) fprintf(stderr, format, args) int main(){    char a[20] =