C 关于宏的一些笔记

FILE, LINE, #line

C语言中的FILE用以指示本行语句所在源文件的文件名.
C语言中的LINE用以指示本行语句在源文件中的位置信息: printf("%d\n",__LINE__);
通过语句#line来重新设定LINE的值: #line 200 //指定下一行的__LINE__为200

__VA_ARGS__

在C99中规定宏也可以像函数一样带可变的参数,如:
#define LOG(format, ...) fprintf(stdout, format, __VA_ARGS__)
其中,…表示可变参数列表,VA_ARGS在预处理中,会被实际的参数集(实参列表)所替换。
同时gcc还支持带可以变参数名的方式(注意:VC不支持):
#define LOG(format, args...) fprintf(stdout, format, args)

同样,args在预处理过程中,会被实际的参数集所替换。其用法和上面的方式一样,只是参数的符号有变。
需要注意的是,上述两种方式的可变参数不能省略,尽管可以传一个空参数进去。说到这里,有必要提一下“##”连接符号的用法,“##”的作用是对token进行连接,上例中format,args,__VA_ARGS都可以看作是token,如果token为空,“##”则不进行连接,所以允许省略可变参数。对上述2个示例的改造:

#define LOG(format, ...) fprintf(stdout, format, ##__VA_ARGS__)  
#define LOG(format, args...) fprintf(stdout, format, ##args)

即然参数可以省略,那么用宏定义一个开关,实现一个输出日志的函数就简单了:

#ifdef DEBUG  
#define LOG(format, ...) fprintf(stdout, ">>>>>" format "<<<<", ##__VA_ARGS__)  
#else  
#define LOG(format, ...)  
#endif 

example:

#include "stdio.h"

#define LOG_TYPE1(format, ...) do{      \
        printf(format, __VA_ARGS__);    \
                                        \
} while(0)

#define LOG_TYPE2(format, args...) do{  \
        printf(format, args);           \
                                        \
} while(0)


#define LOG_TYPE3(format, ...) do{      \
        printf(format, ##__VA_ARGS__);  \
                                        \
} while(0)


#define LOG_TYPE4(format, args...) do{  \
        printf(format, ##args);         \
                                        \
} while(0)


#define LOG(x) printf("LOG "#x" %d \n", x);

int value = 10;

int main()
{

    printf("hello world. \n");

    //LOG_TYPE1("hello %d \n"); error
    LOG_TYPE1("hello %d \n", 1);

    //LOG_TYPE2("hello \n"); error
    LOG_TYPE2("hello %d \n", 2);

    LOG_TYPE3("hello 3\n");
    LOG_TYPE3("hello %d\n", 3);

    LOG_TYPE4("hello 4\n");
    LOG_TYPE4("hello %d\n", 4);


    LOG(10);
    LOG(value);

    return 0;
}

#与##的用法

使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.

#include<cstdio>
#include<climits>
using namespace std;
#define STR(s)     #s
#define CONS(a,b)  int(a##e##b)
int main()
{
   printf(STR(vck));           // 输出字符串"vck"
   printf("%d\n", CONS(2,3));  // 2e3 输出:2000
   return 0;
}

当宏参数是另一个宏的时候,需要注意的是凡宏定义里有用’#’或’##’的地方宏参数是不会再展开.
即, 只有当前宏生效, 参数里的宏!不!会!生!效 !!!!

如:

#define A          (2)
#define STR(s)     #s
#define CONS(a,b)  int(a##e##b)
printf("int max: %s\n",  STR(INT_MAX));    // INT_MAX #include<climits>
printf("%s\n", CONS(A, A));                // compile error --- int(AeA)

展开后:

printf("int max: %s\n","INT_MAX");
printf("%s\n", int(AeA));

由于A和INT_MAX均是宏,且作为宏CONS和STR的参数,并且宏CONS和STR中均含有#或者##符号,所以A和INT_MAX均不能被解引用。导致不符合预期的情况出现。

解决这个问题的方法很简单. 加多一层中间转换宏. 加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_STR)就能得到正确的宏参数.

#define A           (2)
#define _STR(s)     #s
#define STR(s)      _STR(s)          // 转换宏
#define _CONS(a,b)  int(a##e##b)
#define CONS(a,b)   _CONS(a,b)       // 转换宏

printf("int max: %s\n",STR(INT_MAX));
//输出为: int max:0x7fffffff
//STR(INT_MAX) -->  _STR(0x7fffffff) 然后再转换成字符串; 

printf("%d\n", CONS(A, A));
//输出为:200
//CONS(A, A) -->  _CONS((2), (2))  --> int((2)e(2))

猜你喜欢

转载自blog.csdn.net/u014134138/article/details/81296668