kernel cleanup
前言“goto error”模式因引入不易察觉的资源泄漏而臭名昭著。在已经存在多个展开条件的代码路径中添加新的资源获取约束既繁琐又容易出错。“cleanup”辅助函数可以帮助编译器减轻这种繁琐的工作并有助于维护后进先出LIFO的展开顺序从而避免意外的资源泄漏。前备知识1. 语句表达式在 C 语言中({ ... })并不是标准 C 语言的原生语法而是GNU C 编译器GCC提供的一种扩展语法通常被称为语句表达式Statement Expression。这种语法允许你将一系列语句如变量声明、控制流语句if-else,for,switch等包裹在括号中并将其作为一个整体表达式来使用。返回值该语法块中最后一条语句的结果即为整个({ ... })表达式的返回值。作为右值由于它支持返回值因此可以作为表达式的右值使用这在普通的do { ... } while(0)宏中是无法实现的。与do { ... } while(0)的对比在 C 语言宏封装中除了({ ... })更常见的是do { ... } while(0)。两者的主要区别在于do { ... } while(0)无法返回值不能作为表达式的右值但它是标准 C 语法跨平台兼容性极好。({ ... })支持返回值可以参与复杂的表达式计算但它是 GNU C 扩展在非 GCC 兼容的编译器如某些环境下的 MSVC中可能会报错与逗号表达式对比内部能承载的代码复杂度不同逗号表达式只能包含表达式Expressions。你不能在里面声明变量也不能写if-else、for等控制流语句。语句表达式可以包含任意 C 语句Statements。你可以在里面声明局部变量、写循环、条件判断甚至调用返回void的函数。作用域隔离能力不同逗号表达式没有自己的作用域。如果在里面使用了变量它直接操作的是外部的变量。语句表达式有独立的作用域。在({ ... })内部声明的变量出了这个括号就失效了不会污染外部命名空间。这对于编写安全的宏至关重要。标准支持度不同逗号表达式是ISO C 标准语法任何 C 语言编译器GCC, MSVC, Clang都完美支持。语句表达式是GNU C 扩展语法。如果代码要在不支持 GCC 扩展的编译器如 Windows 下的 MSVC上编译会直接报错。核心应用场景的差异逗号表达式主要用于for循环中同时更新多个变量或者在宏中执行简单的副作用操作如打印日志并返回一个计算值。语句表达式主要用于底层开发如 Linux 内核中的高级宏定义。当宏需要执行多步复杂操作、需要临时变量来避免参数多次求值的副作用且必须返回一个值时语句表达式是唯一的标准替代方案在没有它之前只能借助外部指针参数或复杂的嵌套宏来实现。你可以把逗号表达式理解为“一行代码能写完的简单流水线”而语句表达式则是“一个可以打包成单个零件的小型车间”。2. 标记连接运算符## 字符串化运算符#3. 可变参数宏声明语法类似于可变参数函数逗号后面三个句点...表示一个或多个参数。但常见编译器也允许传递0个参数。[2][3]宏扩展时使用特殊标识符__VA_ARGS__表示所传递的参数的替换。变量宏扩展是指与具有可变自变量数的宏相关的 C99 和标准 C 的两个扩展。 一个扩展是用于将变量参数标识从__VA_ARGS__重命名为用户定义的标识的机制。 当未指定变量自变量时另一个扩展提供了一种方法来除去变量宏中的悬空逗号。使用__VA_ARGS__宏表示可变参数...#define debug(...) printf(__VA_ARGS__)给可以参数取了一个名称argsGNU C扩展语法#define debug(format, args...) printf(format, args)如果可变参数被忽略或为空“##”操作将使预处理器(preprocessor)去除掉它前面的那个逗号#define debug(format, args...) printf(format, ##args)eg: debug(123) printf(123),而不是printf(123,)[这样会引起编译报错]第一部分 DEFINE_FREEDEFINE_FREE(...) - 定义free(或者说cleanup)函数1. _name 名称去标识2. _type: free的数据类型3. _free: 用户自定义的清理语句__free(...) - 使用free(或者说cleanup)函数1. _name: 上面定义提到的标识的名称#define DEFINE_FREE(_name, _type, _free) \ static __always_inline void __free_##_name(void *p) { _type _T *(_type *)p; _free; } #define __free(_name) __cleanup(__free_##_name)return_ptr(p) - 返回p的同时抑制_free()原理 通过一个临时变量保存p变量的指针然后把p设为NULL 返回临时变量保存的p变量的指针 p为NULL 就不会执行_free(). 一般地_free if(_T) kfree(_T);#define __get_and_null(p, nullvalue) \ ({ \ auto __ptr (p); \ auto __val *__ptr; \ *__ptr nullvalue; \ __val; \ }) static __always_inline __must_check const volatile void * __must_check_fn(const volatile void *val) { return val; } #define no_free_ptr(p) \ ((typeof(p)) __must_check_fn((__force const volatile void *)__get_and_null(p, NULL))) #define return_ptr(p) return no_free_ptr(p)第二部分 DEFINE_CLASSDEFINE_CLASS(name, type, exit, init, init_args...): 用于定义 type 析构函数destructor和构造函数constructor的辅助函数helper。 exit 是一个使用 _T 的表达式 -- 类似于上面的 FREE。 init 是 init_args 中的一个表达式其结果为 type EXTEND_CLASS(name, ext, init, init_args...): 将类 name 拓展为 nameext并使用新的构造函数new constructor CLASS(name, var)(args...): 将变量 var 声明为命名类name的实例 CLASS_INIT(name, var, init_expr): 将变量 var 声明为命名类name的实例并使用自定义初始化表达式init_expr。代码 DEFINE_CLASS#define DEFINE_CLASS(_name, _type, _exit, _init, _init_args...) \ typedef _type class_##_name##_t; \ typedef _type lock_##_name##_t; \ static __always_inline void class_##_name##_destructor(_type *p) \ __no_context_analysis \ { _type _T *p; _exit; } \ static __always_inline _type class_##_name##_constructor(_init_args) \ __no_context_analysis \ { _type t _init; return t; } #define CLASS(_name, var) \ class_##_name##_t var __cleanup(class_##_name##_destructor) \ class_##_name##_constructor #define CLASS_INIT(_name, _var, _init_expr) \ class_##_name##_t _var __cleanup(class_##_name##_destructor) (_init_expr)扩展定义类 - EXTEND_CLASS#define EXTEND_CLASS_COND(_name, ext, _cond, _init, _init_args...) \ typedef lock_##_name##_t lock_##_name##ext##_t; \ typedef class_##_name##_t class_##_name##ext##_t; \ static __always_inline void class_##_name##ext##_destructor(class_##_name##_t *_T) \ { if (_cond) return; class_##_name##_destructor(_T); } \ static __always_inline class_##_name##_t class_##_name##ext##_constructor(_init_args) \ __no_context_analysis \ { class_##_name##_t t _init; return t; } #define EXTEND_CLASS(_name, ext, _init, _init_args...) \ EXTEND_CLASS_COND(_name, ext, 0, _init, _init_args)include/linux/compiler.h /* Format: __UNIQUE_ID_name___COUNTER__ */ //__COUNTER__是一个从0开始的计数器每次使用这个宏时它的值会自动加1 #define __UNIQUE_ID(name) \ __PASTE(__UNIQUE_ID_, \ __PASTE(name, \ __PASTE(_, __COUNTER__))) include/linux/compiler_types.h #define ___PASTE(a, b) a##b #define __PASTE(a, b) ___PASTE(a, b) include/linux/compiler_attributes.h #define __always_inline inline __attribute__((__always_inline__)) #define __cleanup(func) __attribute__((__cleanup__(func))) ​

相关新闻

Phaser 3游戏开发必备:Catch The Cat中的精灵与场景管理

Phaser 3游戏开发必备:Catch The Cat中的精灵与场景管理

Phaser 3游戏开发必备:Catch The Cat中的精灵与场景管理 【免费下载链接】phaser-catch-the-cat An HTML5 game Catch The Cat powered by Phaser 3 项目地址: https://gitcode.com/gh_mirrors/ph/phaser-catch-the-cat Catch The Cat是一款基于Phaser 3开发…

2026/10/14 20:06:01 阅读更多 →
VCS NLP 低功耗验证系列(七):Debug 深度专题——LP_MSG 消息词典与实战定位方法

VCS NLP 低功耗验证系列(七):Debug 深度专题——LP_MSG 消息词典与实战定位方法

VCS NLP 低功耗验证系列(七):Debug 深度专题——LP_MSG 消息词典与实战定位方法 系列第五篇给出了调试的三层信息金字塔(静态报告 → LP_MSG → Verdi)。本篇是 Debug 的深度续篇,聚焦两块干货:① LP_MSG 消息 ID 全景词典——按上下文分类解读附录 Table 22-1 的自动消…

2026/10/1 7:39:30 阅读更多 →
Letta 安装前先分清三条产品线:Code、Agent SDK 与 legacy server

Letta 安装前先分清三条产品线:Code、Agent SDK 与 legacy server

Letta 最容易踩的坑不是“记忆没有生效”,而是装错了产品面。当前上游 README 明确写着:这个仓库包含 legacy Letta server,活跃开发已经转移到 letta-ai/letta-code;新的 CLI、Agent SDK 和旧的 Python server 不能用同一个安装命…

2026/9/28 2:40:21 阅读更多 →

最新新闻

U-Net论文笔记:编码-解码结构与跳跃连接在医学图像分割中的应用

U-Net论文笔记:编码-解码结构与跳跃连接在医学图像分割中的应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 20:05:13 阅读更多 →
孩子站在父母上面?家庭权力失衡的代价与修复指南

孩子站在父母上面?家庭权力失衡的代价与修复指南

你有没有见过这样的场景:五六岁的孩子因为妈妈没有及时递上水杯,当众对着妈妈又推又喊;妈妈非但不生气,反而赔着笑脸安抚:“他脾气大,顺着就好。”又或者,饭桌上孩子一撅嘴说不吃这个菜&#xf…

2026/10/14 20:05:13 阅读更多 →
多数元素算法的工程本质:从LeetCode到CPU缓存与JVM调优

多数元素算法的工程本质:从LeetCode到CPU缓存与JVM调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 20:05:13 阅读更多 →
嵌入式HTTP客户端自研:状态机与流式解析实战

嵌入式HTTP客户端自研:状态机与流式解析实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 20:05:13 阅读更多 →
STM32寄存器白话手册:从地址映射到位操作实战

STM32寄存器白话手册:从地址映射到位操作实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 20:05:13 阅读更多 →
软件测试核心指南:从目的原则到BUG生命周期全解析

软件测试核心指南:从目的原则到BUG生命周期全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 20:04:12 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →