在源码位置
kernel/printk/
函数原型
asmlinkage __visible int printk(const char *fmt, ...)
{printk_func_t vprintk_func;va_list args;int r;va_start(args, fmt);/** If a caller overrides the per_cpu printk_func, then it needs* to disable preemption when calling printk(). Otherwise* the printk_func should be set to the default. No need to* disable preemption here.*/vprintk_func = this_cpu_read(printk_func);r = vprintk_func(fmt, args);va_end(args);return r;
}
EXPORT_SYMBOL(printk);
fmt,...用法举个例子
#include "stdio.h"void tfunc(const int fmt,...)
{printf("tfunc...\n");
} int main(void)
{tfunc(12);tfunc(12,13);tfunc(12,13,14);return 0;
}
输出
tfunc...
tfunc...
tfunc...--------------------------------
Process exited after 0.04347 seconds with return value 0
请按任意键继续. . .
再举个例子
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
int maxof(int, ...);
void f(void);/*主函数*/
int main()
{f();exit(EXIT_SUCCESS);
}int maxof(int n_args, ...)
{register int i;int max=0, a=0;va_list ap;va_start(ap, n_args);max = va_arg(ap, int);printf("max:%d a:%d n_args:%d\n",max,a,n_args);for(i = 1; i < n_args; i++){if((a = va_arg(ap, int)) > max){max = a;}printf("[%d] max:%d a:%d\n",i,max,a);}va_end(ap);return max;
}void f(void)
{int i = 5;int j = 26;printf("\nmax:%d\n",maxof(3,i,j,13));
}
输出
max:5 a:0 n_args:3
[1] max:26 a:26
[2] max:26 a:13max:26--------------------------------
Process exited after 0.0439 seconds with return value 0
请按任意键继续. . .
说点自己的理解
作为初学者,第一次看到
fmt,...
这样的写法,心里就会有点懵逼,但是实际上,你把它作为C语言的一个知识点,记下来了,就没有那么困难了。既然作为可变参数标识,那么函数体里面,自然也需要解析的方法,我上面写的那个例子,就是解析的方法。
不管是Linux 内核里面的printk函数,还是我们平时调试打印的printf函数,他们都是一样的原理。
解析可变参数
解析就离不开这三个宏
va_list ap;
va_start(ap, n_args);
va_end(ap);
这里面需要涉及到一些技巧,这篇文章里面就不解析说明了,printf 和printk里面使用的还有些差异,无非就是C语言的奇淫异巧,把这种普通人理解不了的东西形容为降龙十八掌,九阴真经,我觉得并不为过。
Linux 驱动打印日志加上自己的TAG
好了,直接上代码就好了,我们平时打印的时候都是直接用一个printk,也没有经过封装,代码这种东西,你要是把它看作是一个艺术品也并不为过,所以很多人谈到一个词,叫做技艺,你自己把这种知识点都掌握了,自己的技艺也就会得到提升了。
#define LOG_TAG "[ES7243]: %s() line: %d "
#define Log(fmt, args...) printk(KERN_INFO LOG_TAG fmt, __FUNCTION__, __LINE__, ##args)
## 这个符号的作用
在C语言里面,## 有两个作用
在函数里面和可变参数一起使用,如果可变参数没有传参,这个符号就把前面的 「,」去掉,这样编译就不会出错。
如果是宏里面使用,就起到一个拼接字符的作用
举个例子
#include<stdio.h>#define LOG_TAG "[ES7243]: %s() line: %d "
#define func(fmt, ...) printf(LOG_TAG fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#define acpi_handle_debug( fmt, ...) printf( fmt, ##__VA_ARGS__)
#define debug(...) printf(__VA_ARGS__)#define _TEST_(x) x##2
int main()
{int i = 23;func("adf:%d\n",++i);debug("123:%d\n",++i);acpi_handle_debug("4444\n");func("%d\n",_TEST_(1));return (0);
}
输出
[ES7243]: main() line: 12 adf:24
123:25
4444
[ES7243]: main() line: 16 12--------------------------------
Process exited after 0.03505 seconds with return value 0
请按任意键继续. . .
推荐阅读:
专辑|Linux文章汇总
专辑|程序人生
专辑|C语言
嵌入式Linux
微信扫描二维码,关注我的公众号