一:可变参数使用:

printf(fmt, ...)

#define DPRINTF(fmt, args...) printf(fmt, ##args)
args...表示fmt之后的参数可以是零个或者多个。

二:#和##只能在宏定义中使用
       #是把宏参数变为一个字符串,##是把两个宏参数连接在一起
1.

#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)));  // 输出:12printf("%s\n",g(f(1,2)));  // 输出:f(1,2)printf("%s\n",g(1));       // 输出:1printf("%d\n", f(1,2));    // 输出:12(数值)return 0;
}

分析:
第 9行:#1 将1转换为字符串输出
第10行:1##2 将1和2连接结果为12,12是数字,故输出时用%d。注意并没有将12转换为字符串,如果需要将12作为字符串输出,需要再次使用h(a)这个宏,即第7行。
第 7行:因为h(a)是普通的宏(即没有#和##的宏),所以h(f(1,2))即是h(12),然后调用g(12),结果是字符串12
第 8行:因为g(a)是直接将a转换为字符串,所以将f(1,2)转换为字符串

2.

#include <stdio.h>#define f(a,b) a##b#define h(a,b) f(a,b)int main()
{printf("%s\n", h("hello", "world"));return 0;
}  

编译时错误信息:
error: pasting ""hello"" and ""world"" does not give a valid preprocessing token
   printf("%s\n", f("hello", "world"));

原因分析:
根据C标准,用##操作后的结果必须是一个已经预定义过的符号,否则就是未定义的。
预定义的符号:头文件名, 等式, 预处理数字, 字符常数, 字符串值, 标点符号, 单个非空字符
具体参考:https://www.cnblogs.com/wb-DarkHorse/p/3588787.html

3. 上面出错的场景是自己想象当参数是字符串时,宏函数调用结果是什么样,以下是可能的一种使用场景。

参考:http://gcc.gnu.org/onlinedocs/gcc-4.3.3/cpp/Concatenation.html#Concatenation

#include <stdio.h>#define COMMAND(name) {#name, name##_command}void quit_command(void) {return;
}  void help_command(void) {return;
}
struct command
{char *name;void (*function) (void);
};  int main()
{struct command commands[] = {COMMAND (quit),COMMAND (help),};return 0;
} 

程序正常运行。

#define # ##使用相关推荐

  1. 非本地类型不能定义方法 cannot define new methods on non-local type time.Duration

    能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法 ? 参见下面的代码演示 : package mainimport "time"type MyDurati ...

  2. C++ 笔记(32)— 预处理、文件包含include、宏替换define、条件包含ifndef、define

    C/C++预处理器在源代码编译之前对其进行一些文本性质的操作. 它的主要任务包括删除注释 . 插入 #include 指令包含的文件的内容 . 定义和替换由 #defme 指令定义的符号以及确定代码的 ...

  3. C++ #define(宏定义)的使用

    C++ 宏定义 #define命令是C++语言中的一个宏定义命令,它用来将一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本. 宏定义的一般形式 #define <宏名& ...

  4. C++ 笔记(07)— 常量(字面常量、const定义常量、constexpr 定义常量、enum 定义常量、define 定义常量)

    在 C++ 中,常量类似于变量,只是不能修改.与变量一样,常量也占用内存空间,并使用名称标识为其预留的空间的地址,但不能覆盖该空间的内容. 常量可以是任何的基本数据类型,可分为整型数字.浮点数字.字符 ...

  5. const与define相比优点_const与#define的区别、优点

    const与#define的区别 编译器处理方式不同 define宏是在预处理阶段展开. 补充:预处理器根据以#开头的命令,修改原始的程序.比如我们常见的#include 命令告诉处理器读取系统头文件 ...

  6. define的多行定义

    在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义.那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍. 宏定义中允许包含两行以上命 ...

  7. C++中typedef和define的区别

    typedef和#define的用法与区别 一.typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: ...

  8. c 宏定义用法#define

    转自:https://blog.csdn.net/boring_wednesday/article/details/78756696 宏定义 语法     #define name Stuff #de ...

  9. typedef和define具体的详细区别

    1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错.例如: #define PI 3.141 ...

  10. 深度分析define预处理指令

    #define语句 预处理 宏替换 --以上出自<C语言入门经典(第四版)> #和## --出自<C语言程序设计:现代方法(第2版)> #undef取消定义 --以上出自< ...

最新文章

  1. VMware里装XP 没有找到硬盘驱动器
  2. Oracle中on和where的区别
  3. 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败
  4. ubuntu 启动进入initramfs错误解决办法
  5. 权限管理----用户与角色关系
  6. Ubuntu下RamDisk使用
  7. java计算交点高程_卡西欧9860CG20图形计算程序(直线相交求交点坐标程序、距离后方交会带高程程序)...
  8. 计算机数字雨教程视频,股票配资火爆cmd什么意思(cmd命令数字雨)
  9. html插入mkv,mkv导入到PR中该怎么做?
  10. Maven安装与Maven HelloWorld入门实例
  11. NFT开拓IP授权新模式
  12. PHP性能 - php_performance - by llia alshanetsky
  13. 李宏毅老师机器学习第二部分:回归问题
  14. 地图坐标概念 html,普通地图坐标
  15. 《人月神话》-人月神话
  16. 自定义Camera系列之:TextureView + Camera2
  17. Java 面试总结之二
  18. gfoj 22的应急救援
  19. matlab ode45画延时,ode45求解微分方程并画图
  20. 基于JAVA携手同游旅游社交平台计算机毕业设计源码+系统+数据库+lw文档+部署

热门文章

  1. CODEVS 1690 开关灯
  2. jetson-inference error code 10 internal error (could not find any implementation for node) #1499
  3. 网约车壁垒超过想象,美团打车陷进退两难地步
  4. 微信浏览器 WeixinJSBridge API
  5. 关于电话号码对应单词
  6. 深入了解iOS中的OOM(低内存崩溃)
  7. 163邮箱设置smtp密码步骤
  8. 有趣的数学题,回家解决
  9. 干货来了丨四大板块构建纵深防御体系,保障工业网络安全
  10. 20美亚团队赛,镜像+解析,由于时间不多,只做pc+内存+恶意程序。