看printk引發的一點思考

在源碼位置

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:13

max: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

微信掃描二維碼,關注我的公衆號

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章