当前位置: 首页 > news >正文

C 语言 宏定义 :字符串化 stringify 的应用

字符串化

  • 通过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 的应用

字符串化 通过C 语言的宏&#xff08;MICRO&#xff09;&#xff0c;可以把数值或者一段字符的组合&#xff0c;转换为字符串。 因为 C语言的宏在【预处理】阶段就展开了&#xff0c;所以可以实现一些比较使用的功能&#xff0c;比如一些数据的初始化操作 比如定义一个宏&…...

代替swagger的api接口神器

自动化API文档-APIFOX 文章作者&#xff1a;老杨 一&#xff1a;概述 大家在后端开发开发过程中&#xff0c;最痛恨的两天事情&#xff1a;1.写文档&#xff0c;2.别人不写文档。而我们后端开发&#xff0c;必定经历的事情就是要和前端&测试对接&#xff0c;我们需要把我…...

2月12日,30秒知全网,精选7个热点

///北京首批29家药店开通异地参保直接结算服务试点药店已覆盖北京市东城区、西城区、朝阳区、海淀区、丰台区和石景山区&#xff0c;为来京就医的外省市参保人员提供便利///杭州召开平台经济健康高质量发展座谈会落实更有针对性的政策供给、提供“店小二”“保姆式”服务、建立…...

HTML img和video object-fit 属性

简介 Css中object-fit主要是应用到img标签和Video标签的&#xff0c;来控制显示缩放效果的。 首先我们存在一张图片&#xff0c;原始图片的尺寸是 1080px x 600px, 展示效果如下&#xff1a; 如果我们的css样式中的img大小设定并不能满足图片的原始大小&#xff0c;比如我们的…...

Pascal版本的 - freopen

参数 filename -- 这是包含要打开的文件的名称的字符串。 mode -- 这是包含文件访问模式的字符串。它包括 - 高级编号模式&说明1个 “r” 打开文件进行读取。该文件必须存在。 2个 “w” 创建一个用于写入的空文件。如果已存在同名文件&#xff0c;则删除其内容并将该文件…...

STM32单片机OLED显示

OLED接口电路STM32单片机OLED显示程序源代码#include "sys.h"#define OLED_RST_Clr() PCout(13)0 //RST#define OLED_RST_Set() PCout(13)1 //RST#define OLED_RS_Clr() PBout(4)0 //DC#define OLED_RS_Set() PBout(4)1 //DC#define OLED_SCLK_Clr()PCout(15)0 //SCL…...

备战金三银四,软件测试面试题(全)

1.B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行&#xff0c;可以实现跨平台&#xff0c;客户端零维护&#xff0c;维护成本低&#xff0c;但是个性化能力低&#xff0c;响应速度较慢 C/S响应速度快&#xff0c;安全性强&#xff0c;一般应用于局域网中&#xff0c;因…...

硬件篇-配置

机箱->239元 机箱选用的itx迷你机箱&#xff0c;为了后期nas方便拓展选了4盘位&#xff0c;该机箱还是比较符合我的预期的&#xff0c;颇有种麻雀虽小五脏俱全的感觉&#xff0c;机箱可以安装matx主板和itx主板&#xff0c;还是比较方便的&#xff0c;机箱带三个大散热风扇&…...

网页内容 中文乱码 解决办法

原因 是因为没有网页没有设置charset是utf-8 解决办法 <!DOCTYPE html> <html lang"en"><head><!-- 这一个标签不能少 --><meta charset"UTF-8" /><body></body> </html>...

【C++之容器篇】造轮子:模拟实现vector类

目录前言一、项目结构1. vector的简介2. 项目结构二、vector的底层结构三、默认成员函数(Member functions)1. 构造函数(1)无参构造函数(2)使用n个值来构造对象(3)使用一段迭代器区间来进行初始化(4)测试构造函数2. 拷贝构造函数&#xff08;现代写法&#xff09;3. 析构函数4.…...

C++中的右值引用与移动构造函数

1.右值引用右值引用是 C11 引入的与 Lambda 表达式齐名的重要特性之一。它的引入解决了 C 中大量的历史遗留问题&#xff0c; 消除了诸如 std::vector、std::string 之类的额外开销&#xff0c; 也才使得函数对象容器 std::function 成为了可能。1.1左值、右值的纯右值、将亡值…...

Swift如何使用依赖注入进行解藕

Swift 中可以使用依赖注入&#xff08;Dependency Injection&#xff09;来解耦组件之间的依赖关系。依赖注入是一种设计模式&#xff0c;指的是在运行时&#xff0c;将一个组件所依赖的其他组件通过构造函数或者属性注入的方式传递给该组件。 例如&#xff0c;有两个组件 A 和…...

合宙ESP32S3-CORE开发板|保姆级|Arduino IDE|windows11|esp32S3支持库|helloword例程:Arduino 环境搭建

Arduino主页网址&#xff1a; Software | Arduino 以windows11版本为例&#xff1a; Arduino IDE最新版本为2.0.3 左边的按钮是直接下载&#xff08;免捐赠&#xff09;&#xff1a; 下载安装完成后&#xff0c;更改软件默认语言&#xff1a; 默认的库是不支持ESP32的&#…...

CMake中target_precompile_headers的使用

CMake中的target_precompile_headers命令用于添加要预编译的头文件列表&#xff0c;其格式如下&#xff1a; target_precompile_headers(<target><INTERFACE|PUBLIC|PRIVATE> [header1...][<INTERFACE|PUBLIC|PRIVATE> [header2...] ...]) # 1 target_preco…...

SpringCloud和微服务介绍

SpringCloud介绍 SpringCloud是在SpringBoot的基础上构建的,用于简化分布式系统构建的工具集。 该工具集为微服务架构中所涉及的配置管理,服务发现,智能路由,断路器,微代理和控制总线等操作提供了一种简单的开发方式。 SpringCloud中包含了多个子项目&#xff1a; Spring …...

Qt源码编译过程中配置文件中的选项说明

文章目录选项说明默认值顶级安装目录-prefix 部署目录&#xff0c;如目标设备上所示。/usr/local/Qt-$QT_VERSION-extprefix 安装目录&#xff0c;如主机上所示。SYSROOT/PREFIX-hostprefix [dir]主机上运行的生成工具的安装目录。如果未给定[dir]&#xff0c;则将使用当前构建…...

Mysql 增删改查(一) —— 查询(条件查询where、分页limits、排序order by、分组 group by)

查询 select 可以认为是四个基本操作中使用最为频繁的操作&#xff0c;然而数据量比较大的时候&#xff0c;我们不可能查询所有内容&#xff0c;我们一般会搭配其他语句进行查询&#xff1a; 假如要查询某一个字段的内容&#xff0c;可以使用 where假如要查询前几条记录&#…...

VScode 结合clangd 构建linux源代码阅读环境

1、背景介绍上一篇文章&#xff1a;VScode 结合Global构建linux源代码阅读环境 &#xff0c;介绍了在VS Code工具中通过remote-ssh远程登陆到Linux远程服务器&#xff0c;使用Global构建linux源代码阅读环境&#xff0c;对linux kernel代码进行解析&#xff0c;实现全局搜索、自…...

web应用 —— JavaScript

Web应用(acwing) 三、JavaScript 1.JS的调用方式与执行顺序 ①使用方法 HTML页面中任意位置加上<script type"module"></script>标签即可 常见使用方式&#xff1a; 直接在<script type"module"></script>标签内写JS代码。直…...

SSM整合SpringSecurity简单使用

一、SpringSecurity 1.1 什么是SpringSecurity Spring Security 的前身是 Acegi Security &#xff0c;是 Spring 项目组中用来提供安全认证服务的框架。(官网地址) Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别是使用领先的J2EE解决方案-Spring框架开发…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...