字符串化

  • 通过C 语言的宏(MICRO),可以把数值或者一段字符的组合,转换为字符串。

  • 因为 C语言的宏在【预处理】阶段就展开了,所以可以实现一些比较使用的功能,比如一些数据的初始化操作

  • 比如定义一个宏,传入的宏的参数是一个 func 函数名,经过宏的层层处理,可以把这个函数名以字符串的方式取出来,并赋值给结构体的 字符指针成员

示例:

        struct rt_init_desc{const char* fn_name;const init_fn_t fn;};#define INIT_EXPORT(fn, level)                                                       \const char __rti_##fn##_name[] = #fn;                                            \RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn." level) = \{ __rti_##fn##_name, fn};
  • 这里的 INIT_EXPORT 的 作用是 在 段中初始化一个数据结构:代码可以通过变量多个这样的数据结构,获取可执行函数的指针,从而实现 【自动初始化】机制。

  • 这个操作有两个特点:(1)代码得到简化 (2)fn 函数名【字符串化】然后组合成一个新的字符串,对数据成员 const char *fn_name 进行初始化

字符串化

  • 宏定义中,通过一个 # 就可以把 一串字符,转换为字符串,这里的一串字符,可以是一个数值,可以是一个函数指针(函数名)

  • 如:#fn ,就把 fn 这个参数,转换为 C 语言中的字符串(常量)了

  • 字符串化最经典的 转换宏:

#define __stringify_1(x...)     #x
#define __stringify(x...)       __stringify_1(x)
  • __stringify_1(5) 获取的 是 "5",也就是 5 转换为 字符串 "5"

  • __stringify 的作用更强大,如果传入的参数也是个【宏定义】,会继续展开,并转换

#define STRING_NAME             "5"
#define DEV_DEMO_NAME1           __stringify(STRING_NAME)

这时 DEV_DEMO_NAME1 不再是 字符串 “STRING_NAME”,而是 “5”

字符串连接

  • 宏定义中,通过两个 ## 可以把两个字符串连接起来,也就是【拼接】起来

  • __rti_##fn##_name, 如果 fn 为 hello,则 展开后为 __rti_hello_name,这里的 ## 起到了字符串(拼接)连接的作用,展开后 ## 就不存在了

测试一下

#include <stdio.h>#define __stringify_1(x...)     #x
#define __stringify(x...)       __stringify_1(x)#define STRING_NAME             "5"
#define DEV_DEMO_NAME           __stringify(5)
#define DEV_DEMO_NAME1           __stringify(STRING_NAME)
#define DEV_DEMO_NAME2          __stringify(DEVICE_NAME_HELLO)int main()
{printf("%s  enter\n", __func__);printf("%s : DEVICE_NAME : %s \n", __func__, STRING_NAME);printf("%s : DEV_DEMO_NAME : %s \n", __func__, DEV_DEMO_NAME);printf("%s : DEV_DEMO_NAME1 : %s \n", __func__, DEV_DEMO_NAME1);printf("%s : DEV_DEMO_NAME2 : %s \n", __func__, DEV_DEMO_NAME2);return 0;
}
  • 测试环境为:ubuntu 20.04 Linux 环境

  • 编译:$ gcc micro_string_test.c -o micro_string_test

  • 运行效果:

zhangsz@zhangsz-virtual-machine:~/linux/codes/202302/0212$ ./micro_string_test
main  enter
main : DEVICE_NAME : 5
main : DEV_DEMO_NAME : 5
main : DEV_DEMO_NAME1 : "5"
main : DEV_DEMO_NAME2 : DEVICE_NAME_HELLO
  • 简单的解释: #define STRING_NAME "5" 直接定义一个字符串 "5",而不是数值 5
  • __stringify(5) 的作用把 5 转换为 字符串了,这就是普通的 【字符串化】
  • #define DEV_DEMO_NAME2 __stringify(DEVICE_NAME_HELLO),由于 DEVICE_NAME_HELLO 不是一个可以展开的【宏】,所以依旧转换为普通的字符串 DEVICE_NAME_HELLO
  • #define DEV_DEMO_NAME1 __stringify(STRING_NAME),由于 STRING_NAME 是个宏,内容是 "5",所以再次展开为 "5",而不是 STRING_NAME,注意这个 "5" 是有双引号的,因为【宏】是【替换】

小结

  • 在操作系统中,C语言的宏非常的多,有些宏定义,使用起来跟函数相差不多,有些宏的使用,大大简化了代码量,让代码看起来非常的整洁美观

  • 当然过多的【宏】,依旧需要不断的查看展开的效果,过长的的【宏定义】,加大了代码阅读的难度,让代码晦涩难懂

  • 宏定义的函数,不利于软件【单步调试】

C 语言 宏定义 :字符串化 stringify 的应用相关推荐

  1. C语言把宏定义字符串化

    原文链接 有时候想要把一个宏定义的内容嵌入到字符串中去. 例如宏定义: #define RATE 15000 #define STR1(R) #R #define STR2(R) STR1(R)pri ...

  2. c语言宏定义字符串 换行_C语言换行

    (一) 这几天正在看 ATMEL 的 ARM 处理器 AT91SAM7X256 ,在其官方的头文件中发现有如下宏定义: #define SPI0_PINS (AT91C_PA17_SPI0_MOSI ...

  3. C语言-宏定义和字符串

    C语言-宏定义和字符串 定义符号常量(宏定义) 格式 下面我们看看如何在C语言中写宏定义呢 接下来我们看看运行结果吧 关于c语言中的字符串 定义符号常量(宏定义) 把程序中出现的所有标识符,替换为已经 ...

  4. c语言宏定义的连接符##和#转字符串

    c语言宏定义的连接符有哪些 [此问题的推荐答案] (一)宏定义中的## 连接符与# 符 ## 连接符号由两个井号组成,其功能是在带参数的宏定义中将两个子串(token)联接起来,从而形成一个新的子串. ...

  5. C/C++语言宏定义##连接符和符#的使用

    C/C++语言宏定义##连接符和符#的使用     [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/53113187 (一) ...

  6. c语言 宏do while,关于C语言宏定义 使用do{ xxxx }while()

    暂时感觉像是由于":"的原因,关于使用习惯方面的问题!! 下面是copy的: 这样的宏见过么: Cpp代码 #define FOO(x) do {\ some_code_line_ ...

  7. C语言宏定义-跟踪调试宏

    C语言宏定义-跟踪调试宏 文章目录 C语言宏定义-跟踪调试宏 1. 简介 2. 相关宏 3. 例子 1. 简介 标准C语言预处理要求定义某些对象宏,每个预定义宏的名称一两个下划线字符开头和结尾,这些预 ...

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

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

  9. c语言中#39;xd#39;代表什么,关于C语言宏定义的技巧:#39;##39;和#39;###39;

    关于C语言宏定义的技巧:'#'和'##' '#'和'##' '#'和'##'是两个预处理运算符,只能在预处理的过程中使用.在带参数的宏定义中, '#'运算符后面应该跟一个参数,预处理器会把这个参数转换 ...

  10. c语言宏定义技巧和用法,关于C语言宏定义的技巧:'#'和'##'

    关于C语言宏定义的技巧:'#'和'##' '#'和'##' '#'和'##'是两个预处理运算符,只能在预处理的过程中使用.在带参数的宏定义中, '#'运算符后面应该跟一个参数,预处理器会把这个参数转换 ...

最新文章

  1. java float内存结构_Java后端开发岗必备技能:Java并发中的内存模型
  2. autoconfig oracle,ORACLE EBS 执行autoconfig time out
  3. python中用lxml解析html
  4. python项目实战:最简单的图片转字符画
  5. 超图桌面版加载obj 3D模型
  6. VS2015安装简单的C#单元测试
  7. 架构师养成之道-01-知识图谱
  8. linux spyder 目录,linux下创建spyder桌面图标的方法
  9. django新建php文件,在Python的Django框架中创建语言文件
  10. const没define好用 php,3分钟短文|PHP 定义常量,我该用define还是const?这下不迷茫了...
  11. Bitmap尺度变换
  12. C# WinForm程序退出的方法
  13. 保存文件_正确保存Zbrush文件
  14. 质性数据分析软件NVivo教程:自动编码情感
  15. 电信 dns服务器 不稳定,网速不稳定的解决方法:修改本地DNS
  16. [每日一氵] mmSeg 报错 StopIteration
  17. 算法 图8 How Long Does It Take
  18. OL3-Cesium 二三维鼠标事件统一处理
  19. java security_java.security.NoSuchAlgorithmException
  20. 环境变量LC相关设置

热门文章

  1. C++多维数组:存储方式、访问方式和作为函数参数
  2. 【TVOS】媒体融合 智慧乡村——TVOS绍兴试点项目正式启动
  3. 行业便携终端串口扩展方案
  4. java集成华为推送
  5. Shader攻占笔记(八)屏幕特效
  6. 前端项目中上传图片如何实现的
  7. tkinter-Entry详解
  8. vue3项目使用prettier格式化代码
  9. BZOJ 2081 Beads Hash
  10. 换个格式输出整数(Java)