内核中的宏
时间:2022-07-22
本文章向大家介绍内核中的宏,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
简介:
宏是一种抽象(Abstraction),它根据一系列预定义的规则替换一定的文本模式。解释器或编译器在遇到宏时会自动进行这一模式替换。在linux中大量的使用宏,使得代码简洁且技巧性很高,本篇就主要记录一下在linux中比较常用的几种用法。
1.定义固定值,便于快速修改
#define MAX_SIZE 1024
这种例子比较简单且很常用,主要是用于对常量的修饰,避免定义变量,减少对内存的消耗。
2.定制打印的log输出
//format意为格式化的字符串,其内部%[格式化],可被外部变量替换。
#define PRINT_ERR(format,x...)
do{ printk(KERN_ERR "[dx_test] func: %s line: %04d info: " format, __func__, __LINE__, ## x); }while(0)
此修饰主要用于debug时对log的特殊定制。譬如我要知道这个log是在代码哪个地方打印出来了,方便快速定位,减少不必要的查找时间,提高效率。在Android内核中,存在大量的这种定制化log打印输出,例如:
#define LOG_TAG "[bma253] "
#define LOG_FUN() printk(KERN_INFO LOG_TAG"%sn", __FUNCTION__)
#define LOG_INFO(fmt, args...) printk(KERN_INFO LOG_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args)
#define LOG_ERR(fmt, args...) printk(KERN_ERR LOG_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args)
一般一个文件会定义一种log输出的宏函数,其实就是对printk的封装加上该文件的标志,在调试代码时根据输出的log快速定位到代码位置。
3.特殊符号##
//“##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接
#define TYPE1(type,name) type name_##type##_type
#define TYPE2(type,name) type name##_##type##_type
便于封装各种变量名。
4.宏函数
#define MAX( a, b) ( (a) > (b) ?(a) : (b) )
比较常用的一个宏函数,封装后与函数的调用相同。宏函数是直接进行字符串的替换,从而减少函数调用的内存消耗,同时提高运行效率。
5.宏开关
//kernel/arch/arm/configs/project_defconfig
CONFIG_KEYBOARD_GPIO=y
//kernel/drivers/input/keyboard/Makefile
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
内核的裁剪就是依靠宏函数实现的。比如以上例子,当configs中的宏为y时,gpio_keys.c才会被编译。
6.'#'字符串化 “#”的功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量,通过替换后在其左右各加上一个双引号。比如下面代码中的宏:
//来自:https://blog.csdn.net/leon1741/article/details/78149881
#define WARN_IF(EXP)
do {
if (EXP) {
fprintf(stderr, "Warning: " #EXP "/n");
}
} while(0);
在实际使用中,会出现以下替换
WARN_IF (divider == 0);
被替换为:
do {
if (divider == 0) {
fprintf(stderr, "Warning" "divider == 0" "/n");
}
} while(0);
- Angular源码分析之$compile
- TensorFlow实例: 手写汉字识别
- iOS引入JavaScriptCore引擎框架(一)
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(三)搭建步骤
- iOS引入JavaScriptCore引擎框架(二)
- Java基础-03(01).总结运算符、键盘录入、if语句
- 使用git恢复未提交的误删数据
- Java web图片上传和文件上传
- 通过java程序模拟实现地铁票价2+2=12(r3笔记第94天)
- 由objC运行时所想到的。。。
- tensorflow系列笔记:流程,概念和代码解析
- node实现watcher的困境
- Java基础-03(02).总结运算符、键盘录入、if语句
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(十一)数据层优化-druid监控及慢sql记录
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- k8s安装自动证书签发cert-manager letsencrypt
- Android仿Keep运动休息倒计时圆形控件
- android通过led实现手电筒功能
- Android 7.0 手电筒控制实现
- 【STM32H7】第13章 RL-TCPnet V7.X之创建多个TCP客户端
- Android倒计时的开始与停止 剩余时分秒的展示
- 由LFI引起的Zimbra邮件管理系统0day
- Android手电筒兼容各个手机与版本
- 【STM32F429】第13章 RL-TCPnet V7.X之创建多个TCP客户端
- RecyclerView仿应用列表实现网格布局
- Android实现带进度条的WebView
- Android实现记住密码功能
- 【- Flutter Web篇 -】 FlutterUnit web版闪亮登场
- Android简单实现弹幕效果
- 实现 Base64 的编码解码