内核中的宏

Posted H₂O₂

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核中的宏相关的知识,希望对你有一定的参考价值。

简介:

宏是一种抽象(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"%s\\n", __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_defconfigCONFIG_KEYBOARD_GPIO=y
//kernel/drivers/input/keyboard/Makefileobj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o


内核的裁剪就是依靠宏函数实现的。比如以上例子,当configs中的宏为y时,gpio_keys.c才会被编译。


6.\'#\'字符串化“#”的功能是将其后面的宏参数进行字符串化操作,简单说就是在对它所引用的宏变量,通过替换后在其左右各加上一个双引号。比如下面代码中的宏:

// 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);



以上是关于内核中的宏的主要内容,如果未能解决你的问题,请参考以下文章

12_关于flask中的宏

剖析linux内核中的宏-----------offsetof

linux内核中的宏ffs(x)

驱动中的宏定义及预编译指令

内核中的宏定义__init__initdata和__exit__exitdata

学习 C 中的宏的建议