转自:https://www.cnblogs.com/hnrainll/archive/2012/08/15/2640558.html

在查看linux内核源码的过程中,遇到了许多宏,这里面有许多都涉及到"#"和"##",因此,在网上搜索了一些资料,整理如下:

一、一般用法 
我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. 
用法: 
#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; 
}

二、当宏参数是另一个宏的时候 
需要注意的是凡宏定义里有用'#'或'##'的地方宏参数是不会再展开.

1, 非'#'和'##'的情况 
#define TOW      (2) 
#define MUL(a,b) (a*b)

printf("%d*%d=%d\n", TOW, TOW, MUL(TOW,TOW)); 
这行的宏会被展开为: 
printf("%d*%d=%d\n", (2), (2), ((2)*(2))); 
MUL里的参数TOW会被展开为(2).

2, 当有'#'或'##'的时候 
#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("int max: %s\n", "INT_MAX");

printf("%s\n", CONS(A, A));               // compile error  
这一行则是: 
printf("%s\n", int(AeA));

INT_MAX和A都不会再被展开, 然而解决这个问题的方法很简单. 加多一层中间转换宏. 
加这层宏的用意是把所有宏的参数在这层里全部展开, 那么在转换宏里的那一个宏(_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,int型的最大值,为一个变量 #include<climits> 
输出为: 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))

三、'#'和'##'的一些应用特例 
1、合并匿名变量名 
#define  ___ANONYMOUS1(type, var, line)  type  var##line 
#define  __ANONYMOUS0(type, line)  ___ANONYMOUS1(type, _anonymous, line) 
#define  ANONYMOUS(type)  __ANONYMOUS0(type, __LINE__) 
例:ANONYMOUS(static int);  即: static int _anonymous70;  70表示该行行号; 
第一层:ANONYMOUS(static int);  -->  __ANONYMOUS0(static int, __LINE__); 
第二层:                        -->  ___ANONYMOUS1(static int, _anonymous, 70); 
第三层:                        -->  static int  _anonymous70; 
即每次只能解开当前层的宏,所以__LINE__在第二层才能被解开;

2、填充结构 
#define  FILL(a)   {a, #a}

enum IDD{OPEN, CLOSE}; 
typedef struct MSG{ 
  IDD id; 
  const char * msg; 
}MSG;

MSG _msg[] = {FILL(OPEN), FILL(CLOSE)}; 
相当于: 
MSG _msg[] = {{OPEN, "OPEN"}, 
              {CLOSE, "CLOSE"}};

3、记录文件名 
#define  _GET_FILE_NAME(f)   #f 
#define  GET_FILE_NAME(f)    _GET_FILE_NAME(f) 
static char  FILE_NAME[] = GET_FILE_NAME(__FILE__);

4、得到一个数值类型所对应的字符串缓冲大小 
#define  _TYPE_BUF_SIZE(type)  sizeof #type 
#define  TYPE_BUF_SIZE(type)   _TYPE_BUF_SIZE(type) 
char  buf[TYPE_BUF_SIZE(INT_MAX)]; 
     -->  char  buf[_TYPE_BUF_SIZE(0x7fffffff)]; 
     -->  char  buf[sizeof "0x7fffffff"]; 
这里相当于: 
char  buf[11];

【alps_008】:
基本看了一遍,楼主的情况属于一般用法:

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

#include<stdio.h>
#include<string.h>
#define STRCPY(a,b) strcpy(a##_p,#b)   //把第一个参数后边加上字符_p,把第二个参数变成字符串

int main()
{
char var1_p[20];
char var2_p[30];
strcpy(var1_p,"aaaa");
strcpy(var2_p,"bbbb");
         STRCPY(var1,var2);            //等于strcpy(var1_p,"var2");
STRCPY(var2,var1);            //等于strcpy(var2_p,"var1");
printf("%s\n",var1_p);
printf("%s\n",var2_p);
return 0;
}

【jeffer007】:
Token-Pasting Operator (##)

// preprocessor_token_pasting.cpp
#include <stdio.h>
#define paster( n ) printf_s( "token" #n " = %d", token##n )
int token9 = 9;

int main()
{
   paster(9);
}
 
Output
token9 = 9

Stringizing Operator (#) 
// stringizer.cpp
#include <stdio.h>
#define stringer( x ) printf( #x "\n" )
int main() {
   stringer( In quotes in the printf function call ); 
   stringer( "In quotes when printed to the screen" );   
   stringer( "This: \"  prints an escaped double quote" );
}

Output
In quotes in the printf function call
"In quotes when printed to the screen"
"This: \"  prints an escaped double quote"

C语言宏中"#"和"##"的用法的更多相关文章

  1. 宏中"#"和"##"的用法

    一.一般用法 我们使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起. 用法: #include<cstdio> #include<climits> using nam ...

  2. C语言 · C++中map的用法详解

    转载自:http://blog.csdn.net/sunquana/article/details/12576729 一.定义   (1) map<string,   int>   Map ...

  3. C语言宏定义技巧

    出处:http://blog.chinaunix.net/uid-14022540-id-2849095.html 1.宏中"#"和"##"的用法 一.一般用法 ...

  4. c语言宏定义详解

    1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数 ...

  5. [转载]C语言 宏

    当然宏定义非常重要的,它可以帮助我们防止出错,提高代码的可移植性和可读性等. 1,防止一个头文件被重复包含 #ifndef COMDEF_H#define COMDEF_H //头文件内容 …#end ...

  6. C语言宏定义#define用法

    #define是C语言中提供的宏定义命令,其主要目的是为程序员在编程时提供一定的方便,并能在一定程度上提高程序的运行效率,但学生在学习时往往不能 理解该命令的本质,总是在此处产生一些困惑,在编程时误用 ...

  7. C语言宏定义时#(井号)和##(双井号)的用法

    C语言中如何使用宏C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念).下面对常遇到的宏的使用问题做了简单总结. 关于#和## 在C语言的宏中,#的功能是将其后面 ...

  8. JAVA语言中冒号的用法

    近来由于本人要介入android平台的开发,所以就买了本JAVA语言的书学习.学习一段时间来,我的感觉是谭浩强就是厉害,编写的<C编程语言>系列丛书不愧是经典.书中对C语言的介绍既系统又全 ...

  9. C语言(C++语言)中##(两个井号)和#(一个井号)用法[转]

    文章来源:http://blog.csdn.net/starboybenben/article/details/49803315 C语言(C++语言)中的宏(Macro)属于编译器预处理的范畴,属于编 ...

随机推荐

  1. exynos4412—UART裸板复习

    我们通过RS232来做实验. 通过电平转换芯片, 连接至核心板: 即:GPA0_0  GPA0_1     配置引脚为串口专用模式: 然后看 ULCONn  [31:0]       0x3 设置串口 ...

  2. 『Python基础-9』元祖 (tuple)

    『Python基础-9』元祖 (tuple) 目录: 元祖的基本概念 创建元祖 将列表转化为元组 查询元组 更新元组 删除元组 1. 元祖的基本概念 元祖可以理解为,不可变的列表 元祖使用小括号括起所 ...

  3. SAS中的宏语言

    一.sas 宏变量 1) 宏变量属于SAS宏语言,与普通变量的区别是可以独立于DATA步 2) 可以再SAS程序中除数据行之外的任何地方定义并使用宏变量 3) %let语句定义宏变量并分配一个值给宏变 ...

  4. Hibernate-关系映射

    1.为什么用Hibernate框架: java程序数据保存的变化: * 内存存在:java基础中, 数据保存在内存中,只在内存中暂时存在 * 文件保存:有io/流之后,数据可以保存到文件中 * 数据库 ...

  5. Dinic算法最大流入门

    例题传送门 Dinic算法是网络流最大流的优化算法之一,每一步对原图进行分层,然后用DFS求增广路.时间复杂度是O(n^2*m),Dinic算法最多被分为n个阶段,每个阶段包括建层次网络和寻找增广路两 ...

  6. 北京Uber优步司机奖励政策(1月22日

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  7. ORB-SLAM(六)MapPoint与Map

    地图点可以通过关键帧来构造,也可以通过普通帧构造,但是最终,必须是和关键帧对应的,通过普通帧构造的地图点只是临时被Tracking用来追踪用的. 构造函数(地图点3D坐标及其参考帧): // 参考帧是 ...

  8. lesson 20 pioneer pilots

    lesson 20 Pioneer pilots driver pilot rider cyclist 骑自行车的人 介词后不加that cover + 距离 = travel 了一段距离 by su ...

  9. TPO-10 C2 Return a literature book

    TPO-10 C2 Return a literature book 第 1 段 1.Listen to a conversation between a student and an employe ...

  10. 前端开发工程师 - 04.页面架构 - CSS Reset & 布局解决方案 & 响应式 & 页面优化 &规范与模块化

    04.页面架构 第1章--CSS Reset 第2章--布局解决方案 居中布局 课堂交流区 水平列表的底部对齐 如图所示,一个水平排列的列表,每项高度都未知,但要求底部对齐,有哪些方法可以解决呢? & ...