马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
pr_* 宏
在之前的文章讲到printk的使用方法,我们发现通过printk宏打各个级别的日记非常繁琐,以是在Linux内核中基于printk宏又新界说了一些宏,比方在 include/linux/printk.h 中的如下界说:- #define pr_emerg(fmt, ...) printk(KERN_EMERG fmt, ##__VA_ARGS__)
- #define pr_alert(fmt, ...) printk(KERN_ALERT fmt, ##__VA_ARGS__)
- #define pr_crit(fmt, ...) printk(KERN_CRIT fmt, ##__VA_ARGS__)
- #define pr_err(fmt, ...) printk(KERN_ERR fmt, ##__VA_ARGS__)
- #define pr_warn(fmt, ...) printk(KERN_WARNING fmt, ##__VA_ARGS__)
- #define pr_notice(fmt, ...) printk(KERN_NOTICE fmt, ##__VA_ARGS__)
- #define pr_info(fmt, ...) printk(KERN_INFO fmt, ##__VA_ARGS__)
复制代码 比方:- pr_err("Disk error occurred!\n");
复制代码 等价于:- printk(KERN_ERR "Disk error occurred!\n");
复制代码 pr_debug 与 pr_devel
- pr_debug:
- #ifdef DEBUG
- #define pr_debug(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__)
- #else
- #define pr_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
- #endif
复制代码
- 只有在 DEBUG 选项开启 (#define DEBUG) 时才会打印日记。
- 否则会被优化为空(no_printk),不影响性能。
- pr_devel:
- #ifdef CONFIG_DYNAMIC_DEBUG #define pr_devel(fmt, ...) printk(KERN_DEBUG fmt, ##__VA_ARGS__)
- #else
- #define pr_devel(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
- #endif
复制代码
- 作用雷同 pr_debug,但受 CONFIG_DYNAMIC_DEBUG 选项控制,实用于动态调试日记。
printk 和 pr_* 宏的关系
- printk 是内核日记的底层实现,直接用于输出日记信息,必要手动指定 KERN_* 级别。
- pr_* 宏是 printk 的封装,使代码更简便、可读性更强,不必要手动添加 KERN_* 级别。
- pr_debug 和 pr_devel 只有在特定编译选项启用时才会收效,实用于调试阶段。
代码示例
- static int __init my_init(void)
- {
- printk(KERN_INFO "This is a test message using printk\n");
- pr_info("This is a test message using pr_info\n");
- return 0;
- }
复制代码 这两种方式终极的结果是一样的,但 pr_info 更简便,保举使用 pr_* 宏。
printk VS pr_*
方法作用需手动加 KERN_*是否保举printk直接打印日记是否(代码冗长)pr_*更简便的 printk 封装否是pr_debug仅在 DEBUG 选项启用时收效否仅用于调试pr_devel仅在 CONFIG_DYNAMIC_DEBUG 启用时收效否仅用于动态调试在 Linux 内核开发中,保举使用 pr_* 宏来替换 printk,以进步代码可读性和维护性。
宏中的参数详解
在- #define pr_emerg(fmt, ...) printk(KERN_EMERG fmt, ##__VA_ARGS__)
复制代码 这个宏界说中,参数部门 fmt, ... 以及 ##__VA_ARGS__ 的作用如下:
参数部门
- #define pr_emerg(fmt, ...) printk(KERN_EMERG fmt, ##__VA_ARGS__)
复制代码
- fmt:格式化字符串,雷同 printf 中的格式字符串,比方 "System is down!\n"。
- ...(可变参数):体现零个或多个额外参数,用于格式化 fmt 中的占位符,如 %d、%s 等。
示例:- pr_emerg("System failure at %d!\n", 42);
复制代码 睁开后酿成:- printk(KERN_EMERG "System failure at %d!\n", 42);
复制代码 ##__VA_ARGS__ 作用
##__VA_ARGS__ 是 GCC 预处置惩罚器 提供的特殊语法,它的作用是 处置惩罚变参为空的情况,克制语法错误。
如果 pr_emerg 被调用时没有可变参数,比方:- pr_emerg("System is down!\n");
复制代码 直接睁开为:- printk(KERN_EMERG "System is down!\n");
复制代码 由于 __VA_ARGS__ 为空,## 会移除前面多余的 ,,包管不会出现 printk(KERN_EMERG "System is down!\n", ); 这种错误。
如果 ##__VA_ARGS__ 不存在,调用 pr_emerg("Hello") 大概会睁开成:- printk(KERN_EMERG "Hello", );
复制代码 如许会导致编译错误。
##__VA_ARGS__ 实用场景
- 有变参 时,正常睁开:
- pr_emerg("Error code: %d\n", 404);
复制代码 睁开为:
- printk(KERN_EMERG "Error code: %d\n", 404);
复制代码 - 无变参 时,去掉多余逗号:
- pr_emerg("Critical failure!\n");
复制代码 睁开为:
- printk(KERN_EMERG "Critical failure!\n");
复制代码 代码示例
- #define pr_emerg(fmt, ...) printk(KERN_EMERG fmt, ##__VA_ARGS__)
- void test() {
- pr_emerg("System halted\n"); // 无变参
- pr_emerg("Error code: %d\n", 500); // 有变参
- }
复制代码 睁开后:- void test() {
- printk(KERN_EMERG "System halted\n");
- printk(KERN_EMERG "Error code: %d\n", 500);
- }
复制代码 小结
语法作用fmt必须参数,格式字符串...可选参数,支持多个变参__VA_ARGS__代表全部通报的变参##__VA_ARGS__处置惩罚无变参时自动去掉前面多余的 ,,防止编译错误这使 pr_emerg 兼容 带参数 和 无参数 两种情况,进步了 printk 的机动性和安全性。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|