关于gcc扩展中的宏定义中用 "#" 和 "##"

今天测试了宏定义中的 "#" 和 "##" 的区别。

结果如下:

"#" 代表和一个字符串相连接

"##" 代表和一个符号连接,符号可以是变量,或另一个宏符号。

举例如下:

宏定义如下

(1)

#define DEV_FILE_NAME    "/dev/test_kft"

#define OPEN_FILE(fd, n)    /
{   /
    fd = open(DEV_FILE_NAME #n,O_RDONLY); /
    if(fd < 0) /
    { /
       printf("Open device error/n"); /
        return 0; /
    }   /
}

如此调用:

OPEN_FILE(fd1, 1);
    OPEN_FILE(fd2, 2);
    OPEN_FILE(fd3, 3);
    OPEN_FILE(fd4, 4);
    OPEN_FILE(fd5, 5);
    OPEN_FILE(fd6, 6);

用gcc -E展开后,如下

2299:    { fd1 = open("/dev/test_kft" "1",00); if(fd1 < 0) { printf("Open device error/n"); return 0; } };
2300:    { fd2 = open("/dev/test_kft" "2",00); if(fd2 < 0) { printf("Open device error/n"); return 0; } };
2301:    { fd3 = open("/dev/test_kft" "3",00); if(fd3 < 0) { printf("Open device error/n"); return 0; } };
2302:    { fd4 = open("/dev/test_kft" "4",00); if(fd4 < 0) { printf("Open device error/n"); return 0; } };
2303:    { fd5 = open("/dev/test_kft" "5",00); if(fd5 < 0) { printf("Open device error/n"); return 0; } };
2304:    { fd6 = open("/dev/test_kft" "6",00); if(fd6 < 0) { printf("Open device error/n"); return 0; } };

如果没有定义DEV_FILE_NAME ,就是

2299:    { fd1 = open(DEV_FILE_NAME "1",00); if(fd1 < 0) { printf("Open device error/n"); return 0; } };
2300:    { fd2 = open(DEV_FILE_NAME "2",00); if(fd2 < 0) { printf("Open device error/n"); return 0; } };
2301:    { fd3 = open(DEV_FILE_NAME "3",00); if(fd3 < 0) { printf("Open device error/n"); return 0; } };
2302:    { fd4 = open(DEV_FILE_NAME "4",00); if(fd4 < 0) { printf("Open device error/n"); return 0; } };
2303:    { fd5 = open(DEV_FILE_NAME "5",00); if(fd5 < 0) { printf("Open device error/n"); return 0; } };
2304:    { fd6 = open(DEV_FILE_NAME "6",00); if(fd6 < 0) { printf("Open device error/n"); return 0; } };

所以可以很清楚的看出#n 解析出来的是"n" , 用于连接一个已有的字符串。

(2) 再来看 ## 是什么意思, 宏定义如下:

#define OPEN_FILE(fd, n)    /
{   /
    fd = open(DEV_FILE_NAME ##n,O_RDONLY); /
    if(fd < 0) /
    { /
       printf("Open device error/n"); /
        return 0; /
    }   /
}

调用方式相同。

看宏展开:

2299:    { fd1 = open(DEV_FILE_NAME1,00); if(fd1 < 0) { printf("Open device error/n"); return 0; } };
2300:    { fd2 = open(DEV_FILE_NAME2,00); if(fd2 < 0) { printf("Open device error/n"); return 0; } };
2301:    { fd3 = open(DEV_FILE_NAME3,00); if(fd3 < 0) { printf("Open device error/n"); return 0; } };
2302:    { fd4 = open(DEV_FILE_NAME4,00); if(fd4 < 0) { printf("Open device error/n"); return 0; } };
2303:    { fd5 = open(DEV_FILE_NAME5,00); if(fd5 < 0) { printf("Open device error/n"); return 0; } };
2304:    { fd6 = open(DEV_FILE_NAME6,00); if(fd6 < 0) { printf("Open device error/n"); return 0; } };

现在看清楚了, ##n 的作用是把n直接连接在了一个符号的末尾. 好, 现在我们定义一个符号看看效果。

#define DEV_FILE_NAME1    "/dev/test_kft1"

再展开:

2299:    { fd1 = open("/dev/test_kft1",00); if(fd1 < 0) { printf("Open device error/n"); return 0; } };
2300:    { fd2 = open(DEV_FILE_NAME2,00); if(fd2 < 0) { printf("Open device error/n"); return 0; } };
2301:    { fd3 = open(DEV_FILE_NAME3,00); if(fd3 < 0) { printf("Open device error/n"); return 0; } };
2302:    { fd4 = open(DEV_FILE_NAME4,00); if(fd4 < 0) { printf("Open device error/n"); return 0; } };
2303:    { fd5 = open(DEV_FILE_NAME5,00); if(fd5 < 0) { printf("Open device error/n"); return 0; } };
2304:    { fd6 = open(DEV_FILE_NAME6,00); if(fd6 < 0) { printf("Open device error/n"); return 0; } };

很显然第一个符号被替换了, 因为是符号是宏的缘故。 这样我们也能把这一扩展特性应用在变量上。

关于gcc扩展中的宏定义中用 # 和 ##相关推荐

  1. Makefile中用宏定义进行条件编译(gcc -D)/在Makefile中进行宏定义-D

    在源代码里面如果这样是定义的: #ifdef   MACRONAME //可选代码 #endif 那在makefile里面 gcc   -D   MACRONAME=MACRODEF 或者 gcc   ...

  2. Linux内核源码中使用宏定义的若干技巧

    在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...

  3. Linux 内核中的宏定义

    Linux 内核中的宏定义 rtoax 日期 内核版本:linux-5.10.13 注释版代码:https://github.com/Rtoax/linux-5.10.13 __attribute__ ...

  4. C++中的宏定义详解

    转载自:C++中的宏定义 和 C++宏定义详解 目录 一.#define解析 1 #define命令剖析 1.1   #define的概念 1.2 宏替换发生的时机 1.3 ANSI标准说明了五个预定 ...

  5. NASM汇编程序中的宏定义

    NASM汇编程序中的宏定义 格式如下: %macro 宏名 参数名列表 宏体 %endmacro 如: %macro Descriptor 3 dw %2 & 0FFFFh dw %1 &am ...

  6. 如何在Linux kernel Makefile中添加宏定义

    如何在Linux kernel Makefile中添加宏定义: CFLAGS_object.o += -DMACRO_NAME 在编译object.o时定义宏MACRO_NAME,在kernel中添加 ...

  7. C++中的内联函数和C中的宏定义的区别

    在C++中内联函数: 内联函数即是在函数的声明和和定义前面加上"inline"关键字,内联函数和常规函数一样,都是按照值来传递参数的,如果参数为表达式,如4.5+7.5,则函数将传 ...

  8. [C语言] 在单片机的嵌入式开发中使用宏定义一键开关日志输出/打log调试

    前言 在编写项目时,我们通常需要日志输出来帮助我们追踪程序执行的内容,以便在出现BUG时较为方便的复现,并在调试完成后快速的关闭过于详细的LOG输出,避免干扰使用中的体验,在函数中一个一个的增加pri ...

  9. 关于Linux Kernel中的宏定义likely和unlikely

    在Linux kernel的源代码中,经常能见到if(likely(x))或if(unlikely(x))之类的用法,其确切含义需要说明一下,以便更好的理解kernel的源代码. likely与unl ...

最新文章

  1. 细节决定成败:一个公共类库
  2. 国内的IDC数据中心运营维护前景如何?
  3. linux php-fpm优化 php-fpm.conf 重要参数详解
  4. 静态成员内部类和非静态成员内部类的实例化方式
  5. 走进我的交易室02_交易什么市场
  6. 这就是XcodeGhost作者的原话
  7. smart原则_目标管理:OKR与SMART原则的异同
  8. 智能环境监测产品浪涌防护整改之TVS管
  9. 全国省市区的数据导入
  10. 得到APP之订阅专栏《硅谷来信》和《精英日课》目录
  11. RoaringBitMap学习和实践
  12. 邮件群发平台是什么意思?如何选择邮件群发平台
  13. STM32学习之SPI协议(读写FLASH)
  14. 沐风微信营销水库模型二:建设专属秘密武器库!
  15. 如何将Asp.net 2.0网站部署到服务器
  16. 银光类似web visio的节点连线控件Essential Diagram免费下载地址
  17. 59 Three.js 渲染两个场景和使用不同的相机,渲染在一个场景里面
  18. 信号地和电源地的区别
  19. Android AOA链接(accessory host)
  20. Android安卓逆向工程师

热门文章

  1. 一步步编写操作系统 55 CPL和DPL入门2
  2. 【Tyvj - 1305】最大子序和(单调队列优化dp)
  3. 【CodeForces - 827A】String Reconstruction(并查集合并区间,思维)
  4. 【POJ - 1273】Drainage Ditches(网络流,最大流,模板)
  5. 【牛客 - 331D】炫酷路途(二进制枚举 或 建图方式+最短路 或 dfs)
  6. 【CF#459 A 】Pashmak and Garden (水题)
  7. python bind sock_python 在bind端口之后创建的socket如果不关闭的话会被回收吗?
  8. vue页面取ajax返回值,Vue前端交互模式、Promise用法(回调地狱)
  9. 遍历这些字符串,如果字符串没有包含数字的,就将字符串中的小写字母转成大写字母并打印字符串
  10. 苏宁css代码生成器,【前端】06 - rem + less + 媒体查询 - 制作苏宁首页