关于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扩展中的宏定义中用 # 和 ##相关推荐
- Makefile中用宏定义进行条件编译(gcc -D)/在Makefile中进行宏定义-D
在源代码里面如果这样是定义的: #ifdef MACRONAME //可选代码 #endif 那在makefile里面 gcc -D MACRONAME=MACRODEF 或者 gcc ...
- Linux内核源码中使用宏定义的若干技巧
在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...
- Linux 内核中的宏定义
Linux 内核中的宏定义 rtoax 日期 内核版本:linux-5.10.13 注释版代码:https://github.com/Rtoax/linux-5.10.13 __attribute__ ...
- C++中的宏定义详解
转载自:C++中的宏定义 和 C++宏定义详解 目录 一.#define解析 1 #define命令剖析 1.1 #define的概念 1.2 宏替换发生的时机 1.3 ANSI标准说明了五个预定 ...
- NASM汇编程序中的宏定义
NASM汇编程序中的宏定义 格式如下: %macro 宏名 参数名列表 宏体 %endmacro 如: %macro Descriptor 3 dw %2 & 0FFFFh dw %1 &am ...
- 如何在Linux kernel Makefile中添加宏定义
如何在Linux kernel Makefile中添加宏定义: CFLAGS_object.o += -DMACRO_NAME 在编译object.o时定义宏MACRO_NAME,在kernel中添加 ...
- C++中的内联函数和C中的宏定义的区别
在C++中内联函数: 内联函数即是在函数的声明和和定义前面加上"inline"关键字,内联函数和常规函数一样,都是按照值来传递参数的,如果参数为表达式,如4.5+7.5,则函数将传 ...
- [C语言] 在单片机的嵌入式开发中使用宏定义一键开关日志输出/打log调试
前言 在编写项目时,我们通常需要日志输出来帮助我们追踪程序执行的内容,以便在出现BUG时较为方便的复现,并在调试完成后快速的关闭过于详细的LOG输出,避免干扰使用中的体验,在函数中一个一个的增加pri ...
- 关于Linux Kernel中的宏定义likely和unlikely
在Linux kernel的源代码中,经常能见到if(likely(x))或if(unlikely(x))之类的用法,其确切含义需要说明一下,以便更好的理解kernel的源代码. likely与unl ...
最新文章
- 细节决定成败:一个公共类库
- 国内的IDC数据中心运营维护前景如何?
- linux php-fpm优化 php-fpm.conf 重要参数详解
- 静态成员内部类和非静态成员内部类的实例化方式
- 走进我的交易室02_交易什么市场
- 这就是XcodeGhost作者的原话
- smart原则_目标管理:OKR与SMART原则的异同
- 智能环境监测产品浪涌防护整改之TVS管
- 全国省市区的数据导入
- 得到APP之订阅专栏《硅谷来信》和《精英日课》目录
- RoaringBitMap学习和实践
- 邮件群发平台是什么意思?如何选择邮件群发平台
- STM32学习之SPI协议(读写FLASH)
- 沐风微信营销水库模型二:建设专属秘密武器库!
- 如何将Asp.net 2.0网站部署到服务器
- 银光类似web visio的节点连线控件Essential Diagram免费下载地址
- 59 Three.js 渲染两个场景和使用不同的相机,渲染在一个场景里面
- 信号地和电源地的区别
- Android AOA链接(accessory host)
- Android安卓逆向工程师
热门文章
- 一步步编写操作系统 55 CPL和DPL入门2
- 【Tyvj - 1305】最大子序和(单调队列优化dp)
- 【CodeForces - 827A】String Reconstruction(并查集合并区间,思维)
- 【POJ - 1273】Drainage Ditches(网络流,最大流,模板)
- 【牛客 - 331D】炫酷路途(二进制枚举 或 建图方式+最短路 或 dfs)
- 【CF#459 A 】Pashmak and Garden (水题)
- python bind sock_python 在bind端口之后创建的socket如果不关闭的话会被回收吗?
- vue页面取ajax返回值,Vue前端交互模式、Promise用法(回调地狱)
- 遍历这些字符串,如果字符串没有包含数字的,就将字符串中的小写字母转成大写字母并打印字符串
- 苏宁css代码生成器,【前端】06 - rem + less + 媒体查询 - 制作苏宁首页