Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
C语言
宏定义define
【经验分享】一个实用的C语言宏定义技巧写法
发布于 2022-05-31 22:08:47 浏览:781
订阅该版
[tocm] **【经验分享】一个实用的C语言宏定义技巧写法** ![image.png](https://oss-club.rt-thread.org/uploads/20220531/f24fc0de4794ec45711734fac1b757ab.png) # 1 写在前面 宏定义在 C语言中,是一种很常见的语法;经常阅读开源代码,你会发现,使用好C语言的宏定义,真的可以写出更加整洁,可读性非常高的高质量代码。 本文将描述一个需要使用宏定义技巧来解决的问题场景,希望对大家理解和使用C语言的宏定义有所帮助和提高。 # 2 问题需求 最近恰好在项目开发的过程中,遇到了一个有关宏定义的问题。项目运用的背景如下: > 项目中有个头文件中定义了一个宏定义,比如是 #define CFG_LOGGER_NAME uart > 然后,在某个C文件中需要将这个宏定义转换成对应的字符串类型,即为 **"uart"** ;很明显,如果按以下的几种方式定义,肯定得不到期望的结果: ```c 方式1: #define CFG_LOGGER_NAME_STR "CFG_LOGGER_NAME" 方式2: #define CFG_LOGGER_NAME_STR #CFG_LOGGER_NAME 方式3: #define CFG_LOGGER_NAME_STR ##CFG_LOGGER_NAME ``` # 3 代码实践 ## 3.1 编写代码 为了解决这个问题,特意再次去查看了有关C语言宏定义的语法,终于找到了解决方法,具体的思路是,需要用一个 **“中间宏函数”** 做转换,我们用代码来实践一下。 ```c #include
#include
#define TEST uart #define TO_STR(x) #x #define CFG_LOGGER_NAME uart #define TO_STRING(x) #x #define _CFG_LOGGER_NAME_STR(x) TO_STRING(x) #define CFG_LOGGER_NAME_STR _CFG_LOGGER_NAME_STR(CFG_LOGGER_NAME) /* 这三种都达不到需求 */ #define CFG_LOGGER_NAME_STR1 "CFG_LOGGER_NAME" /* 语法错误:error: stray ‘#’ in program */ //#define CFG_LOGGER_NAME_STR2 #CFG_LOGGER_NAME /* 语法错误: error: '##' cannot appear at either end of a macro expansion */ //#define CFG_LOGGER_NAME_STR3 ##CFG_LOGGER_NAME int main(void) { printf("\r\n%s\r\n", TO_STR(TEST)); printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR); printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR1); //printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR2); //printf("\r\n%s\r\n", CFG_LOGGER_NAME_STR3); return 0; } ``` ## 3.2 结果验证 验证环境如下: ```shell recan@ubuntu:~$ uname -a Linux ubuntu 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux recan@ubuntu:~$ recan@ubuntu:~$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper OFFLOAD_TARGET_NAMES=nvptx-none:hsa OFFLOAD_TARGET_DEFAULT=1 Target: x86_64-linux-gnu Configured with: Thread model: posix gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1) ``` 代码编译: ```shell gcc -o test test.c ``` 结果运行: ```shell recan@ubuntu:~$ ./test TEST uart CFG_LOGGER_NAME ``` 查看宏定义展开后的预处理文件: ```shell recan@ubuntu:~$ gcc -E -o test.i test.c | tail -n 20 test.i # 499 "/usr/include/string.h" 3 4 # 4 "test.c" 2 # 22 "test.c" # 22 "test.c" int main(void) { printf("\r\n%s\r\n", "TEST"); printf("\r\n%s\r\n", "uart"); printf("\r\n%s\r\n", "CFG_LOGGER_NAME"); return 0; } ``` 我们可以看到宏代码的展开是符合我们的预期的,也只有`CFG_LOGGER_NAME_STR` 这一种写法是满足我们问题需求的。 # 4 经验总结 - 宏定义看似很简单,没实践出来的时候,有时候会想不通为什么会这么被展开? - 在gcc编译器下查看宏定义被展开的内容使用的是`-E`选项。 - C语言宏定义中的 “**#**” 和 "**##**" 是有特殊用法的,必须要用于带参数的宏定义中,否则会报语法错误。 - **留个疑问:为何加了一个中间宏函数转了一道手,就能得到预期的内容?** # 5 参考链接 - [C语言的宏定义](http://c.biancheng.net/cpp/html/65.html) - [带参数和不带参数的宏定义](http://c.biancheng.net/view/287.html) # 6 更多分享 > **[架构师李肯](https://recan.blog.csdn.net/?type=blog)** > > 一个专注于嵌入式IoT领域的架构师。有着近10年的嵌入式一线开发经验,深耕IoT领域多年,熟知IoT领域的业务发展,深度掌握IoT领域的相关技术栈,包括但不限于主流RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、主流IoT云平台的对接、嵌入式IoT系统的架构设计等等。拥有多项IoT领域的发明专利,热衷于技术分享,有多年撰写技术博客的经验积累,连续多月获得RT-Thread官方技术社区原创技术博文优秀奖,荣获[CSDN博客专家](https://recan.blog.csdn.net/?type=blog)、CSDN物联网领域优质创作者、[2021年度CSDN&RT-Thread技术社区之星](https://blog.csdn.net/szullc/article/details/123860472)、[RT-Thread官方嵌入式开源社区认证专家](https://club.rt-thread.org/ask/experts.html)、[RT-Thread 2021年度论坛之星TOP4](https://club.rt-thread.org/ask/article/3317.html)、[华为云云享专家(嵌入式物联网架构设计师)](https://bbs.huaweicloud.com/community/usersnew/id_1573655458316259)等荣誉。坚信【知识改变命运,技术改变世界】! 欢迎关注我的[github仓库01workstation](https://github.com/recan-li/01workstation/tree/master/workspace/gcc/gc_section),日常分享一些开发笔记和项目实战,欢迎指正问题。 同时也非常欢迎关注我的CSDN主页和专栏: [【CSDN主页:架构师李肯】](http://yyds.recan-li.cn) [【RT-Thread主页:架构师李肯】](https://club.rt-thread.org/u/18001) [【C/C++语言编程专栏】](https://blog.csdn.net/szullc/category_8450784.html) [【GCC专栏】](https://blog.csdn.net/szullc/category_8626555.html) [【信息安全专栏】](https://blog.csdn.net/szullc/category_8452787.html) [【RT-Thread开发笔记】](https://blog.csdn.net/szullc/category_11461616.html) [【freeRTOS开发笔记】](https://blog.csdn.net/szullc/category_11467856.html) 有问题的话,可以跟我讨论,知无不答,谢谢大家。
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
李肯陪你玩赚嵌入式
2022年度和2023年度RT-Thread社区优秀开源布道师,COC深圳城市开发者社区主理人,专注于嵌入式物联网的架构设计
文章
47
回答
504
被采纳
82
关注TA
发私信
相关文章
1
RT-Thread内存和字符串相关函数与C语言自带的内存和字符串相关函数冲突问题
2
嵌入式RT-thread中初始化线程函数中(void *)entry的意义何在
3
cJSON parse 失败,请问怎么解决?
4
请教一个C语言顺序表的问题,不知道有没有大佬帮吗解答
5
小白请教,关于头文件引用,、、哪些场景需要引用它们?
6
使用中断有warn。。。。。。。。。。。
7
局部变量位置被编译器改写
8
RTthread 两个例程结合在一起会出现incompatible type for argument 2 of 'led_matrix_set_color'
9
有没有在单片机编程使用goto语句的?
10
请问如何读取另一个c文件中的温湿度数据啊
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
6
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部