tqsheng

go.....
随笔 - 366, 文章 - 18, 评论 - 101, 引用 - 0
数据加载中……

define 参数

C99标准之宏定义_可变参数宏_#_##

        在查看Android的log功能代码的时候发现了如下宏定义:

#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))

        参考如下链接和C99标准编写测试代码及输出测试如下:

 

        链接地址:

                 http://topic.csdn.net/u/20090311/22/dada8228-9254-47da-b88a-4895fd83ddde.html

                 http://www.vimer.cn/2010/03/cc%E5%AE%8F%E5%AE%9A%E4%B9%89%E7%9A%84%E5%8F%AF%E5%8F%98%E5%8F%82%E6%95%B0.html

                 http://www.uml.org.cn/c%2B%2B/200902104.asp

                 http://baike.baidu.com/view/1967819.htm?fr=ala0_1

                 http://eelab.tsinghua.edu.cn/book/09-11/856891276060145.html

                 http://blog.csdn.net/chenglian_999/archive/2009/11/04/4765317.aspx

 

        语法解释:

        在最前强调一点,#和##只有在宏定义中有效,其他地方无效

        #(可以称之为hash字符,the # operator,#运算符),它的作用就是将它后面的东西转换成字符串。它的作用可以通过测试代码中的宏定义的#define LOGD部分注释掉的代码和未注释掉的代码互换来进行理解。(红色部分)

        ##的作用是将前后两部分粘合在一起,例子为

#define HASH_HASH STR(# ## #)
#define HASHTEST ####
//--------notice about the space in #define--------------
#define CONTACT(a, b) STR(a ## b)
#define NOSPACE_CONTACT(a, b) STR(a##b)
#define NEW_CONTACT(a,b) newfun(a HASH_HASH b) //a new token is not ever a ##
#define _NEW_CONTACT(a,b) STR(newfun(a HASH_HASH b))
//-------------------------------------------------

        带参数的宏定义的测试也是红色字体部分,参考资料中解释为:

"..."代表可变参数列表, 如果它不是仅有的参数, 那么它只能出现在参数列表的最后. 调用这样的函数宏时, 传递给它的参数个数要不少于参数列表中参数的个数(多余的参数被丢弃).
通过__VA_ARGS__来替换函数宏中的可变参数列表. 注意__VA_ARGS__只能用于函数宏中参数中包含有"..."的情况.

 

        测试代码:

#include <stdio.h>

#define STR(s) #s
//#define LOGD(...) printf(#__VA_ARGS__)
#define LOGD(...) printf(__VA_ARGS__)

#define HASH_HASH STR(# ## #)
#define HASHTEST ####
//--------notice about the space in #define--------------
#define CONTACT(a, b) STR(a ## b)
#define NOSPACE_CONTACT(a, b) STR(a##b)
#define NEW_CONTACT(a,b) newfun(a HASH_HASH b) //a new token is not ever a ##
#define _NEW_CONTACT(a,b) STR(newfun(a HASH_HASH b))
//-------------------------------------------------
HASHTEST
HASH_HASH
NEW_CONTACT(I,m)
CONTACT(I,m)
NOSPACE_CONTACT(c,d)
//------------------------------------------------

int main()
{

        LOGD("This is a test for C99 #define!""/r/n");
        LOGD(STR(Test STR defination)"/r/n");
        LOGD(HASH_HASH"/r/n");
        LOGD(CONTACT(I,m)"/r/n");
        LOGD(NOSPACE_CONTACT(c,d)"/r/n");
        LOGD(_NEW_CONTACT(I,m)"/r/n");
        LOGD(STR(NEW_CONTACT(I,m))"/r/n");
        return 0;

}

 

        使用gcc命令:

gcc -E test.c

        展开宏定义得到如下代码:
HASHTEST
"##"
newfun(I "##" m)
"Im"
"cd"


int main()
{

 printf("This is a test for C99 #define!""/r/n");
 printf("Test STR defination""/r/n");
 printf("##""/r/n");
 printf("Im""/r/n");
 printf("cd""/r/n");
 printf("newfun(I HASH_HASH m)""/r/n");
 printf("NEW_CONTACT(I,m)""/r/n");
 return 0;

}


        屏蔽不规范语法最后编译执行的结果如下:

This is a test for C99 #define!
Test STR defination
##
Im
cd
newfun(I HASH_HASH m)
NEW_CONTACT(I,m)





一般在调试打印Debug信息的时候, 需要可变参数的宏. 从C99开始可以使编译器标准支持可变参数宏(variadic macros), 另外GCC也支持可变参数宏, 但是两种在细节上可能存在区别.
1. __VA_ARGS__
        __VA_ARGS__ 将 "..." 传递给宏 . 如
        #define debug(format, ...) fprintf(stderr, format, __VA_ARGS__)

2. GCC的复杂宏
        GCC使用一种不同的语法,从而可以给可变参数一个名字,如同其它参数一样.
        #define debug(format, args...) fprintf (stderr, format, args)
        这和第一条的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述.

3. ##__VA_ARGS__
        上面两个定义的宏,如果出现 debug("A Message")的时候,由于宏展开后有个多余的逗号,所以将导致编译错误.
        为了解决这个问题,CPP 使用一个特殊的"##"操作,格式如下:
        #define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
        这里,如果可变参数被忽略或为空,"##"操作将使预处理器(preprocessor)去除掉它前面的那个逗号.


posted on 2012-03-19 11:28 tqsheng 阅读(1652) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理