C/C++中“#”和“##”的作用和用法

在C/C++的宏中,”#”的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。

而”##”被称为连接符(concatenator),用来将两个子串Token连接为一个Token。注意这里连接的对象是Token就行,而不一定是宏的变量。还可以n个##符号连接n+1个Token,这个特性是#符号所不具备的。

凡是宏定义里有用’#’或’##’的地方宏参数是不会再展开。

若要使’#’和’##’的宏参数被展开,可以加多一层中间转换宏。加这层宏的用意是把所有宏的参数在这层里全部展开,那么在转换宏里的那一个宏就能得到正确的宏参数。

以下是测试代码:

#include "stdafx.h"
#include <iostream>

using namespace std;

//test1
#define WARN_IF(EXP) 	if (EXP) 	fprintf(stderr, "warning: "#EXP" \n");

//test2
#define STR(s) #s

//test3
#define _STRI(s) #s
#define STRI(s) _STRI(s) //转换宏

//test4
#define paster(n) printf("token"#n" = %d\n", token##n)

//test5
#define _CONS(a, b) int(a##+##b)
#define CONS(a, b) _CONS(a, b) //转换宏

//test6
#define  _GET_FILE_NAME(f)   #f
#define  GET_FILE_NAME(f)    _GET_FILE_NAME(f)  //转换宏

//test7
#define  _TYPE_BUF_SIZE(type)  sizeof #type
#define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type) 

//test8
#define D(x)  #@x  //仅对单一标记转换有效

int main(int argc, char* argv[])
{
	//test1
	int divider = 0;
	WARN_IF(divider == 0);//warning: divider == 0 

	//test2
	printf("int max: %s\n", STR(INT_MAX));//int max: INT_MAX

	//test3
	printf("int max: %s\n", STRI(INT_MAX));//int max: 2147483647

	//test4
	int token9 = 9;
	paster(9);//token9 = 9 

	//test5
	int A = 15, B = 2;
	printf("A + B = %d\n", CONS(A, B));//A + B = 17

	//test6
	char  FILE_NAME[] = GET_FILE_NAME(__FILE__);
	cout<<FILE_NAME<<endl;//"e:\\temp\\tmp.cpp"

	//test7
	cout<<TYPE_BUF_SIZE(INT_MAX)<<endl;//11

	//test8
	cout<<D(F)<<endl;//F

	cout<<"ok!"<<endl;

	return 0;
}

以上内容整理自:

1.      http://keendawn.blog.163.com/blog/static/888807432011527113124144/

2.      http://www.cppblog.com/just51living/archive/2011/08/08/152752.html

3.      http://blog.csdn.net/acs713/article/details/6891837

时间: 2024-08-28 15:33:43

C/C++中“#”和“##”的作用和用法的相关文章

SpringMVC中 -- @RequestMapping的作用及用法

一.@RequestMapping 简介 在Spring MVC 中使用 @RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置 <servlet> <servlet-name>servletName</servlet-name> <servlet-class>ServletClass</servlet-class> </servlet> <ser

Java中volatile的作用以及用法

volatile让变量每次在使用的时候,都从主存中取.而不是从各个线程的“工作内存”. volatile具有synchronized关键字的“可见性”,但是没有synchronized关键字的“并发正确性”,也就是说不保证线程执行的有序性. 也就是说,volatile变量对于每次使用,线程都能得到当前volatile变量的最新值.但是volatile变量并不保证并发的正确性. =========================分割线1===============================

js中return的作用及用法

这里面的return含有一些细节知识: 例如:onClick='return add_onclick()'与 onClick='add_onclick()'的区别 JAVASCRIPT在事件中调用函数时用return返回值实际上是对window.event.returnvalue进行设置. 而该值决定了当前操作是否继续.当返回的是true时,将继续操作.当返回是false时,将中断操作. 而直接执行时(不用return).将不会对window.event.returnvalue进行设置所以会默认

Oracle中存储过程的作用和用法

存储过程是Oracle开发者在数据转换或查询报表时经常使用的方式之一.它就是想编程语言一样一旦运行成功,就可以被用户随时调用,这种方式极大的节省了用户的时间,也提高了程序的执行效率.存储过程在数据库开发中使用比较频繁,它有着普通SQL语句不可替代的作用.所谓存储过程,就是一段存储在数据库中执行某种功能的程序.其中包含一条或多条SQL语句,但是它的定义方式和PL/SQL中的块.包等有所区别.存储过程可以通俗地理解为是存储在数据库服务器中的封装了一段或多段SQL语句的PL/SQL代码块.在数据库中有

php中的set_magic_quotes_runtime()作用和用法

set_magic_quotes_runtime 用来设置php.ini文件中的magic_quotes_runtime值,当遇到反斜杆(\).单引号(').双引号(")这样一些的字符定入到数据库里,又不想被过滤掉,使用这个函数,将会自动加上一个反斜杆(\),保护系统和数据库的安全. magic_quotes_runtime 是php.ini里的环境配置变量,0和false表示关闭本功能,1和true表示打开本功能.当magic_quotes_runtime打开时,所有外部引入的数据库资料或者文

C#中Dictionary的作用及用法讲解

Dictionary<string, string>是一个泛型 他本身有集合的功能有时候可以把它看成数组 他的结构是这样的:Dictionary<[key], [value]> 他的特点是存入对象是需要与[key]值一一对应的存入该泛型 通过某一个一定的[key]去找到对应的值 举个例子: 1 //实例化对象 2 3 Dictionary<int, string> dic = new Dictionary<int, string>(); 4 5 //对象打点

Java中static变量作用和用法详解

static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被类的所有实例共享. 只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们.因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象. 用public修饰的static成员变量和成员方法本质是

django中related_name的作用和用法

其实可以就理解为,一对多关系拿对象的解决 可以把引用理解为主从关系 主引用从,即一对多 , 注意外键字段是放在多的一端的,比如一个班级class 有很多同学 students,那么就在students类里面设置class字段值是外键类型 从students拿class数据很好拿, studets.class就拿到了 但是从class 拿students数据 就不好拿了,当然也可以拿,默认的方式是class.students_set.all() 也可以拿到 不过这样麻烦,简单一点就是设置一个rel

java中import、package作用和用法

  有些人写了一阵子 Java,可是对於 Java 的 package 跟 import 还是不 太了解很多人以為原始码 .java 档案中的 import 会让编译器把所 import 的程式通通写到编译好的 .class 档案中,或是认為 import 跟 C/C++ 的 #include 相似,实际上,这是错误的观念. 让我们先了解一下,Java 的 package 到底有何用处. 其实,package 名称就像是我们的姓,而 class 名称就像是我们的名字 .package 名称有很多