#define简单妙用

1:__FILE__,__LINE__,宏展开,中间层宏

__FILE__是编译器预定义宏,表示此文件的绝对路径,但是ASCII字符。

假如你想将__FILE__转换成宽字符。

或许你想这样

 

#define __WFILE__  L##__FILE__

wchar_t pszFilePath[]=__WFILE__;

 

这样的话编译器会提示说,“L__FILE__”: 未声明的标识符。

这是为什么?

如果##后的参数本身也是一个宏的话,##会阻止这个宏的展开,也就是只替换一次。需要加一层中介完成代换,就想这样。

 

#define __WFILE3__(x) (L##x)
#define __WFILE2__(x) __WFILE3__(x)
#define __WFILE__  __WFILE2__(__FILE__)

wchar_t pszFilePath[]=__WFILE__;

 

当宏函数的定义中调用了另一个宏函数,预处理器会将其中所有可展开的宏展开。这样就可以了。

再看一个具有迷惑性的错误宏定义:

#define __WFILE1__(x) (L##x)

#define __WFILE__  __WFILE1__(__FILE__)

wchar_t pszFilePath[]=__WFILE__;

这样呢,编译器同样会报出L__FILE__未定义,也就是说L_FILE__不是一个字符串。

让我们一步一步看看预处理器是如何做的吧?

1.当预处理器到达wchar_t pszFilePath[]=__WFILE__;它发现宏定义,然后执行展开__WFILE1__( __FILE__ )

2.同时发现__FILE1__又是一个宏定义,那么展开(L##__FILE1__)

为什么预处理器没有展开__FILE1__呢,你可能觉得,自己已经添加了中间步骤。但实际上没有,我们单单看__WFILE1__( __FILE__ ),不关其他定义,你就会发现,这个宏定义根据前面的规则是绝对不会展开的,所以前面的__WFILE__根本没有起到中间代换的作用。

所以总结起来的话,从__FILE__第一次出现,必须要经过中间一层宏。中间一层宏是指__FILE__必须出现在宏声明中(宏的左侧),同时宏的定义(即宏定义右侧)也是一个宏。那么这个宏才能称为中间层。这个中间层才能起到展开__FILE__的作用。

 

下面看下个错误的字符串宏定义例子

 

#define SHOWLINENUMW3(x) (L##x)
#define SHOWLINENUMW2(x) SHOWLINENUMW3(#x)
#define SHOWLINENUMW(x)  SHOWLINENUMW2(x)
#define __WLINE__ SHOWLINENUMW(__LINE__)

 

#define __WFILE3__(x) (L##x)
#define __WFILE2__(x) __WFILE3__(x)
#define __WFILE__  __WFILE2__(__FILE__ )

 

#define __N__ (__WFILE__ __WLINE__)

 

TCHAR szFileName[]=__N__;

 

注意L##x是带括号的。编译器提示:项不会计算为接受 1 个参数的函数。

 

为什么会出错呢?那是因为对多个单独的字符串连接时,不能用括号括起来括起任意一个。当然单独一个可以。

如:

wchar_t szTemp[]=(L"nihao"); //第一种 可以

wchar_t szTemp[]=(L"nihao") (L"tahao");//第二种 不可以。

wchar_t szTemp[]=L"nihao" L"woyehao";//第三种 可以

 

而前面给出的错误的例子经过宏替换这后就相当于第二种,所以编译器会报告错误。我们需要将(L##x)改成L##x才能正确运行。

 

所以正确的例子是:

#define SHOWLINENUMW3(x) L##x
#define SHOWLINENUMW2(x) SHOWLINENUMW3(#x)
#define SHOWLINENUMW(x)  SHOWLINENUMW2(x)
#define __WLINE__ SHOWLINENUMW(__LINE__)

 

#define __WFILE3__(x) L##x
#define __WFILE2__(x) __WFILE3__(x)
#define __WFILE__  __WFILE2__(__FILE__ )

 

#define __N__ (__WFILE__ __WLINE__)

 

TCHAR szFileName[]=__N__;

2:__VA_ARGS__

__VA_ARGS__好像是c99标准加进来的宏定义功能,可能用于不变参数宏

#define MY_PRINTF( x,...) printf( x, ##__VA_ARGS__ )

其中...表示可变参数列表,__VA_ARGS__则是表示前面的可变参数列表,其中##用于在没可变参数列表时去掉前面的逗号。编译器会识别出##,并去掉前面的逗号。

如果没有##:

#define MY_PRINTF( x,...) printf( x, __VA_ARGS__ )

MY_PRINTF( "Hello World" );

宏展开后:

printf( "Hello World", );

这样的编译器会抱怨警告,甚至编译不过。采用##之后就可以了。而且##本身也是连接符。

当然有时我们可以直接:

#define MY_PRINTF(...) printf(__VA_ARGS__)

此时就不需要##,因为前面没有逗号。

暂时总结自己知道的这么多的,以后再补充吧。

时间: 2024-10-31 05:20:36

#define简单妙用的相关文章

gcc-一个简单的 #define i++ 问题

问题描述 一个简单的 #define i++ 问题 #include <stdio.h> #define product(x) (x*x) int main() { int i=3,j,k; j = product(i++); k = product(++i); printf("j=%d,k=%d",j,k); return 0; } 为啥答案是 12,49? GCC环境 解决方案 I love sneakers!(最少分配一个问题)[Java] 一个关于i++ 的问题Ho

#define和typedef的简单区别及使用

/* ============================================================================ Name : TestDefine.c Author : lf Version : Copyright : Your copyright notice Description : #define和typedef的简单区别及使用 1 两者执行时间的差异 #define是宏定义,发生在预处理阶段,即编译之前. 它只进行简单而机械的替换,而不进

佩奇和布林:谷歌成功13妙招做最简单产品

谷歌创始人谢尔盖·布林和拉里·佩奇 导语:谷歌是近十年来最为成功的科技公司, 美国科技博客Businessinsider周四撰文分析了创始人谢尔盖·布林(Sergey Brin)和拉里·佩奇(Larry Page)让谷歌成为科技巨头的13种妙招.以下是文章全文:过去十年,谷歌成为了 众多公司攻击的对象.谷歌连续多年蝉联最佳雇主,成为年轻专业人士最向往的公司,他们的名字也一直和搜索联系在一起. 那么佩奇和布林是如何使谷歌成为科技巨头的呢,以下是他们使用过的13种妙招:选择不喜欢的商业伙伴第一印象

PhotoShop图层样式的妙用网页设计简单实用教程

图层样式是每个设计师都常用的功能,合理巧妙的应用能大大的节省我们的工作时间,提高工作效率, 今天我来分享一下平时工作中对图层样式应用的一点技巧,希望对新手有点帮助,我们的目标:简单实用. 一.按钮篇 在制作页面的按钮时,我们希望保证设计风格的情况下,能够最大程度适应各类修改情况,比如:尺寸,色调,形状的修改等等. 下面来谈谈几种风格按钮的制作方法 网站上最常见的按钮,用图层样式来做也最简单:渐变叠加+投影,没难度. 下面再来一个比较常见,有两明暗双描边的按钮. 分类: PS入门教程

《众妙之门——用户体验设计的秘密》一1.3 问题解决的简单步骤

1.3 问题解决的简单步骤 研究用户,学习他们解决问题的方法,掌握他们的交互方式.完成这些之后,设计模式将会变得明晰,设计流程将会更加简化.如果设计已经完成,重新通过这种办法来审阅一遍设计也是个不错的主意. 这些步骤不光能解决设计问题,同时也是一切问题的普遍性解决方案--真的非常有效: (1)确定并理解出现的问题. (2)制定计划,以图修正. (3)实施计划. (4) 检查一下解决方案是否行之有效(如果没有,说明计划有问题,或者对问题的理解不够透彻). 其实,用户遇到问题时,也是这样将问题分解,

越减越妙:简单表格的再设计

设计 从 So the Necessary May Speak 一文延伸阅读,找到了包括 Luke W.Andrey Smagin.Deva Prasad 多人的再设计,转贴图如下: 设计小结: 如果用户是想一览所有的数据,那么 Luke 的设计较好,视线垂直移动且范围集中 如果用户是想查看某个确定的值,那么 Deva Prasad 的设计较好,突出重点: 如果所有数据没有权重,那么增大字号或者改变颜色会增加干扰: 原则:根据具体情况,通过降低干扰和视线移动的距离来减少用户的视觉疲劳.

C语言在linux内核中do while(0)妙用之法

为什么说do while(0) 妙?因为它的确就是妙,而且在linux内核中实现是相当的妙,我们来看看内核中的相关代码: #define db_error(fmt, ...) \ do { \ fprintf(stderr, "(error): "); \ fprintf(stderr, fmt, ##__VA_ARGS__); \ } while (0) 这只是个普通的调试信息的输出,有人便会认为,你这不是多此一举吗?去掉do while(0)不一样也实现了吗?其实不然,我们看看例子

简单java在线测评程序

简单java程序在线测评程序 v一.前言 大家过年好!今年的第一篇博客啊!家里没有网,到处蹭无线!日子过得真纠结!因为毕设的需求,简单写了一个java程序在线测评程序,当然也可以在本地测试. v二.思路 首先简单介绍一下思路: 1.得到java程序的源代码,不需要导入包.得到源码之后在前面加入"import java.util.*;" 2.通过JavaCompiler对象可以帮助我们将java源代码编译成class文件. 3.通过DiagnosticCollector对象可以获得编译过

简单字符串转换

在做字符串.文本操作时,我们时常会需要在wchar_t *和char *之间做转换或搭桥.直 接用API,参数太多不容易记住,常常要查文档,浪费不少时间.为了自己方便,对简单的转 换写了一个简单的转换包装类.下次或者用得着,帖代码做为保存. 顺便提一下:发现有个东西很好用,std::stringstream系列 (#include < sstream >):其实,流式操作用起来都很happy,还有iostream.fstream:还有TCP的数据也是流 式的. 头文件:string.h #pr