#include <stdio.h>
#define f(a,b) a##b
#define g(a)  #a
#define h(a) g(a)
int main()
{
  printf("%s/n",h(f(1,2)));
  printf("%s/n",g(f(1,2)));
  return 0;
}

首先需要了解#和##的意义。
 
#  将右边的参数做整体的字符串替换。
 
#define g(a)  #a
 
则g(hello world) à hello world; g(sleep(1)) à sleep(1)
 
对于#的参数,即便是另一个宏,也不展开,仍然作为字符串字面信息输出。
 
所以,g(f(1,2)) à f(1,2)
 
对于h(f(1,2)),由于h(a)是非#或##的普通宏,需要先宏展开其参数a,即展开f(1,2)为12,则h(a) 宏替换为h(12),进而宏替换为g(12), 进而宏替换为12 
 
## 将左右两边的参数做整体的字符串拼接替换。
 
#define f(a,b) a##b
 
则f(1,2) à 12, f(i,1) à i1
 
同#,对于##的参数,即便是另一个宏,也不展开,仍然作为字符串字面信息输出。
 
此外,有一个限制是,经过##替换后的内容必须能够作为一个合法的变量。
 
以上f(i,1) à i1中,如果程序中没有i1的定义,或者通过f(1,i)构成1i,则即便是通过了宏替换,也不能编译通过。

--------------------------------------------------------------------------------

日常实践中,##是常用的替换。尤其在通过C的函数指针来模拟动态绑定时大有用处。
 
下面是从stackoverflow(具体id记不清了)上摘取的一个例子。

struct command
{
  char *name;
  void (*function) (void);
};
struct command commands[] =
{
  { "quit", quit_command },
  { "help", help_command },
  ...
};

构造一个这样的commands数组,是为了在后续的设计中,可以通过交互式的字符串输入,来动态地执行相应的函数。字符串自身作为前缀,”_command”作为后缀。

手工构造这样第一个commands数组显得非常冗余,还容易造成不必要的拼写错误。下面来看看这个宏替换版本。

#define COMMAND(NAME)  { #NAME, NAME ## _command } 
struct command commands[] =
{
COMMAND (quit),
COMMAND (help),
...
};

清晰了很多!

转载于:https://www.cnblogs.com/catgatp/p/8604245.html

#和##在宏替换中的作用相关推荐

  1. python宏替换_#和##在宏替换中的作用

    #include #define f(a,b) a##b #define g(a)  #a #define h(a) g(a) int main() { printf("%s/n" ...

  2. do {...} while (0) 在宏定义中的作用

    有篇文章解释很清楚:do {...} while (0) in macros 然后,一位女程序媛把它翻译了一遍,排版清晰,想省力的看这边.do {...} while (0) 在宏定义中的作用

  3. #define定义标识符——定义宏——替换规则——##的作用——#undef

    首先介绍预定义符号 FILE //进行编译的源文件 LINE //文件当前的行号 DATE //文件被编译的日期 TIME //文件被编译的时间 STDC //如果编译器遵循ANSI C,其值为1,否 ...

  4. 宏定义中#号和##号的使用

    在技术群中有人提了一个问题:如何定义一个宏,打印传递过来的参数的地址.这很简单,像下面这样 [objc] view plaincopy #define pl(param)  NSLog(@" ...

  5. 宏定义中的 ## ... __VA_ARGS__

    宏定义中的##操作符和... and _ _VA_ARGS_ _ 1.Preprocessor Glue: The ## Operator 预处理连接符:##操作符 Like the # operat ...

  6. C语言字符串中使用宏替换

    1 背景 在定义一个字符串时,希望有一部分内容可以使用宏替换.当尝试使用如下方式来实现时,发现并不能达到目的. #define XXX programmer char str[] = "I ...

  7. C语言宏定义中#号的作用

    C语言宏定义中#号的作用 前言 #号的作用 前言 最近,在阅读uboot的源码过程中,发现了一段宏定义代码: #define U_BOOT_CMD_MKENT_COMPLETE(_name, _max ...

  8. Java中的宏变量,宏替换详解。

    转载自 Java中的宏变量,宏替换详解. 群友在微信群讨论的一个话题,有点意思,特拿出来分享一下. 输出true false 来看下面这段程序,和群友分享的大致一样. public static vo ...

  9. c程序语言符号的作用,c语言宏定义中的#,##,#@及\符号的作用

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

最新文章

  1. 如何快速定位当前数据库消耗CPU最高的sql语句?
  2. DKHadoop人力资源大数据解决方案架构
  3. LruCache缓存处理及异步加载图片类的封装
  4. android线程栈默认大小,线程的默认最大堆栈大小 - Internet Information Services | Microsoft Docs...
  5. 《精彩绝伦的CSS》读书笔记(二)
  6. java map removeall_Java删除Map中元素
  7. js 高级 call()
  8. ie6的png24问题
  9. Angular 导致公司损失数十亿美元!
  10. linux/work
  11. c++整人小程序(附源码)
  12. 配置嵌入式Servlet容器
  13. 《OpenGL编程指南(原书第9版)》——第3章 3.0OpenGL绘制方式
  14. ANSYS or Abaqus? 一个过来人的工作感悟
  15. Python学习_案例for循环嵌套
  16. Windows 10开启Teredo隧道连接IPV6
  17. 【编程题】【Scratch三级】2021.06 躲球游戏
  18. Android使用svg格式图片,并改变图片颜色
  19. 科普|股东需要对企业债务承担连带责任
  20. 体育赛事直播系统的实践之路

热门文章

  1. sql express 无法启动服务_在Windows2012下安装SQL Server 2005无法启动服务的解决办法...
  2. openssh升级后root_又一root神器停止营业!时至今日你还需要root吗
  3. LeetCode算法入门- 3Sum -day9
  4. linux 内存规划,生产场景怎么对linux系统进行合理规划分区?
  5. oracle数据库sql的执行过程,Oracle体系结构之SQL语句的执行过程
  6. svg 地图_找地图素材?有这个网站就够了!
  7. 打开python环境_windows下切换Python运行环境。
  8. dz论坛连接mysql数据库_dz论坛搬家后连接数据库等教程
  9. oracle 换字段顺序,修改ORACLE的字段顺序
  10. .deploy 文件 php,关于php:Heroku deploy自动删除服务器文件?