define宏定义中的#,##,@#及符号

摘要:
define宏定义中的#,##,@#及符号在#define中,标准只定义了#和##两种操作。如:#defineexampleNumnum##nintnum9=9;使用:intnum=exampleNum;将会扩展成intnum=num9;注意:1.当用##连接形参时,##前后的空格可有可无。如:#defineexampleNumnum##n相当于#defineexampleNumnum##n2.连接后的实际参数名,必须为实际存在的参数名或是编译器已知的宏定义//preprocessor_token_pasting.cpp#include#definepasterprintf_sinttoken9=9;intmain(){paster;}运行结果:token9=93、@#字符化操作符。只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。例如,可以定义如下宏:#defineXNAMEx##n#defineXNAMEx##n宏调用XNAME会展开成x4。

define宏定义中的###@#符号

#define中,标准只定义了###两种操作。#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串。

1#stringizing)字符串化操作符。其作用是:将宏定义中的传入参数名转换成用一对双引号括起来参数名字符串。其只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。

如:

#defineexample(instr)printf("theinputstringis: %s ",#instr)

#defineexample1(instr)#instr

当使用该宏定义时:

example(abc);在编译时将会展开成:printf("theinputstringis: %s ","abc");

stringstr=example1(abc);将会展成:stringstr="abc"

注意:

对空格的处理

a。忽略传入参数名前面和后面的空格。

如:str=example1(abc);将会被扩展成str="abc"

b.当传入参数名间存在空格时,编译器将会自动连接各个子字符串,用每个子字符串中只以一个空格连接,忽略其中多余一个的空格。

如:str=exapme(abcdef);将会被扩展成str="abcdef"

2##token-pasting)符号连接操作符

宏定义中:参数名,即为形参,如#definesum(a,b)(a+b);中ab均为某一参数的代表符号,即形式参数。

##的作用则是将宏定义的多个形参成一个实际参数名。

如:

#defineexampleNum(n)num##n

intnum9=9;

使用:

intnum=exampleNum(9);将会扩展成intnum=num9;

注意:

1.当用##连接形参时,##前后的空格可有可无。

如:#defineexampleNum(n)num##n相当于#defineexampleNum(n)num##n

2.连接后的实际参数名,必须为实际存在的参数名或是编译器已知的宏定义

//preprocessor_token_pasting.cpp

#include<stdio.h>

#definepaster(n)printf_s("token"#n"=%d",token##n)

inttoken9=9;

intmain()

{

paster(9);

}

运行结果:

token9=9

3@#charizing)字符化操作符。

只能用于有传入参数的宏定义中,且必须置于宏定义体中的参数名前。作用是将传的单字符参数名转换成字符,以一对单引用括起来。

#definemakechar(x)#@x

a=makechar(b);

展开后变成了:

a='b';

4行继续操作符

当定义的宏不能用一行表达完整时,可以用""表示下一行继续此宏的定义。

注意:换行不能切断单词,只能在空格的地方进行。

宏定义的特殊符号###-[C++]

1.利用宏参数创建字符串:#运算符

在类函数宏(function-likemacro)的替换部分中,“#”符号用作一个预处理运算符,它可以把语言符号(token)转化为字符串。例如,如果x是一个宏参量,那么#x可以把参数名转化为相应的字符串。该过程称为字符串化。

说明:类函数宏就是带参数的宏。类函数宏的定义中,用圆括号括起来一个或多个参数,随后这些参数出现在替换部分。
#include<stdio.h>
#definePSQR(x)printf("Thesquareof"#x"is%d. ",(x)*(x))

intmain(void)
{
inty=5;

PSQR(y);
PSQR(2+4);

return0;
}

//输出:
Thesquareofyis25.//"y"代替#x
Thesquareof2+4is36.//"2+4"代替#x
#include<stdio.h>
#definePSQR(x)printf("Thesquareof"#x"is%d. ",(x)*(x))

intmain(void)
{
inty=5;

PSQR(y);
PSQR(2+4);

return0;
}

//输出:
Thesquareofyis25.//"y"代替#x
Thesquareof2+4is36.//"2+4"代替#x
#defineSTRING2(x)#x
#defineSTRING(x)STRING2(x)

#defineWQwangqi

#pragmamessage(STRING2(WQ))//WQ(字符串)
#pragmamessage(STRING(WQ))//wangqi(字符串)
#defineSTRING2(x)#x
#defineSTRING(x)STRING2(x)

#defineWQwangqi

#pragmamessage(STRING2(WQ))//WQ(字符串)
#pragmamessage(STRING(WQ))//wangqi(字符串)
2.预处理器的粘合剂:##运算符

#运算符一样,##运算符可以用于类函数宏的替换部分。另外,##运算符还可用于类对象宏(object-likemacro)的替换部分。这个运算符把两个语言符号组合成单个语言符号。例如,可以定义如下宏:
#defineXNAME(n)x##n
#defineXNAME(n)x##n
宏调用XNAME(4)会展开成x4

说明:类对象宏就是用来代表值的宏。如,#definePI3.141593中的PI
#include<stdio.h>
#defineXNAME(n)x##n
#definePRINT_XN(n)printf("x"#n"=%d ",x##n);

intmain(void)
{
intXNAME(1)=14;//变为intx1=14;
intXNAME(2)=20;//变为intx2=20;
PRINT_XN(1)//变为printf("x1=%d ",x1);
PRINT_XN(2)//变为printf("x2=%d ",x2);

return0;
}

//输出:
x1=14
x2=20
#include<stdio.h>
#defineXNAME(n)x##n
#definePRINT_XN(n)printf("x"#n"=%d ",x##n);

intmain(void)
{
intXNAME(1)=14;//变为intx1=14;
intXNAME(2)=20;//变为intx2=20;
PRINT_XN(1)//变为printf("x1=%d ",x1);
PRINT_XN(2)//变为printf("x2=%d ",x2);

return0;
}

//输出:
x1=14
x2=20
#define__T(x)L##x
#define_T(x)__T(x)
#define_TEXT(x)__T(x)

#defineWQ"wangqi"

#pragmamessage(__T(WQ))//LWQ(标识符)
wcout<<_T(WQ);//wangqi(宽字节字符串)
#define__T(x)L##x
#define_T(x)__T(x)
#define_TEXT(x)__T(x)

#defineWQ"wangqi"

#pragmamessage(__T(WQ))//LWQ(标识符)
wcout<<_T(WQ);//wangqi(宽字节字符串)
3.语言符号

从技术方面看,系统把宏的主体当作语言符号(token)类型字符串,而不是字符型字符串。C预处理器中的语言符号是宏定义主体中的单独的词(word。用空白字符把这些词分开。例如:
#defineFOUR2*2
#defineFOUR2*2
这个定义中有一个语言符号:即序列2*2。但是:
#defineSIX2*3
#defineSIX2*3
这个定义中有三个语言符号:2*3

在处理主体中的多个空格时,字符型字符串和语言符号型字符串采用不同方法。考虑下面的定义:
#defineEIGHT4*8
#defineEIGHT4*8
把主体解释为字符型字符串时,预处理器用4*8替换EIGHT。也就是说,额外的空格也当作替换文本的一部分。但是,当把主体解释为语言符号类型时,预处理器用由单个空格分隔的三个语言符号,即4*8来替换EIGHT。换句话说,用字符型字符串的观点看,空格也是主体的一部分;而用语言符号字符串的观点看,空格只是分隔主体中语言符号的符号。在实际应用中,有些C编译器把宏主体当作字符串而非语言符号。在比这个实例更复杂的情况下,字符与语言符号之间的差异才有实际意义。

顺便提一下,C编译器处理语言符号的方式比预处理器的处理方式更加复杂。编译器能理解C的规则,不需要用空格来分隔语言符号。例如,C编译器把2*2当作三个语言符号。原因是C编译器认为每个2都是一个常量,而*是一个运算符。

免责声明:文章转载自《define宏定义中的#,##,@#及符号》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇vue+go.js项目流程图 (外呼项目案例)C#-数组截取的方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

详解C/C++预处理器 .

C/C++编译系统编译程序的过程为预处理、编译、链接。预处理器是在程序源文件被编译之前根据预处理指令对程序源文件进行处理的程序。预处理器指令以#号开头标识,末尾不包含分号。预处理命令不是C/C++语言本身的组成部分,不能直接对它们进行编译和链接。C/C++语言的一个重要功能是可以使用预处理指令和具有预处理的功能。C/C++提供的预处理功能主要有文件包含、宏...

枚举和宏的区别

枚举: 枚举是一种变量类型,枚举基本等效于int类型,占用同样的空间,同样的数值范围,但是枚举通常都是表示常数变量,对枚举变量做一些算术计算通常是编译器不允许的,但是可以加上强制类型转换,本来不在枚举符表里面的值也可以大摇大摆的登堂入室,枚举符表甚至允许数值相等。在没有赋值的引用中,只会是int范围内的垃圾数值,根本就不会是枚举符表中的数值。对于默认的情况...

vi编辑器的学习使用(七)

vi编辑器学习使用之七vi是一个强大的编辑器,他不仅可以用来处理我们平时的文本工作,他还可以用写程序文件。在vi中有许多命令可以方便的完成我们的程序处理工作。在用vi进行程序处理时,vi充分的显示出来了他的强大之处,他可以实现在语法加亮显示,实现自动缩进,实现括号匹配,还可以在程序中实现查找和跳转。我们可以用这样的命令在vi中打开语法加亮显示的功能::sy...

高斯键盘设置指南

高斯键盘设置指南 蓝牙模式 如何打开蓝牙模式 供电 : 蓝牙工作需要供电, 给高斯 GS87-D 供电有两种方式: 键盘背后的开关打到ON; 使用 USB Type-C 电源. 切换模式: 有线和无线模式切换键是 Fn+P 按下 Fn+P 右上角键盘灯闪烁 3 次, 有线模式和蓝牙模式互相切换. 但比较坑的是并没有指示灯表示当前处于有线模式还是蓝...

Xcode 报错:duplicate symbols for architecture x86_64错误分析及解决

1、参与编译的.m文件重复导入。一般是手动往工程中导入源文件时导入在了不同的目录。 解决方法也很简单,在 Target -> build parses -> complie sources,去掉重复的文件即可。 2、导入头文件时,误写为导入.m 文件 即 #import xxx.h 写成了 #import xxx.m 解决方法就是,导入头文...

【easycode】使用说明 &amp;amp; 示例

语法 ## 是模板的注释,不会生成 # 全局的一些设置 $ 使用库函数或者调用全局定义的内容 常用方法 数据库表信息 ${tableInfo} comment 表备注 name 表名 fullColumn 所有列 comment 列备注 name 列名称 type 列类型 pkColumn 主键列 otherColumn 其...