概述

本文假定读者已经了解并使用过C/C++printf()的相关方法,如果对此不太熟悉,可以点击这里了解printf(3)

C 语言中的 printf 一系列方法用于分别向不同受体根据某种格式,传递消息。

  • The functions printf() and vprintf() write output to stdout, the standard output stream;
  • fprintf() and vfprintf() write output to the given output stream;
  • sprintf(), snprintf(), vsprintf(), and vsnprintf() write to the character string str.

printk 是内核中广为人知的函数之一,它是我们在开发内核工具时用于打印消息的标准工具,通常也是跟踪和调试的最基本方法。printk 的设计和 printf 非常相似,但是两者的功能却是天差地别。

  • printk() 具有类似日志级别的概念
  • 格式化字符串虽然在很大程度上与 C99 规范兼容,但并不完全遵循此规范,它有一些扩展和一些限制,在如何正确使用 printk 格式说明
  • printk() 输出的信息重定向到了内核日志缓冲区中,这是一个通过/dev/kmsg 导出到用户空间的环形缓冲区,可以通过使用dmesg命令查看。

proto

printk() 方法通常使用方式如下:

1
printk(KERN_INFO "Message: %s\n", arg);

其中 KERN_INFO 是内核中的日志级别,它被连接到格式化字符串,日志级别并不是一个单独的参数。当前系统可选的日志级别如下:

NameString(Value)Alias function
KERN_EMERG“0”pr_emerg()
KERN_ALERT“1”pr_alert()
KERN_CRIT“2”pr_crit()
KERN_ERR“3”pr_err()
KERN_WARNING“4”pr_warn()
KERN_NOTICE“5”pr_notice()
KERN_INFO“6”pr_info()
KERN_DEBUG“7”pr_debug() and pr_devel() if DEBUG is defined
KERN_DEFAULT“”/
KERN_CONT“c”pr_cont()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* printk - print a kernel message
* @fmt: format string
*
* This is printk(). It can be called from any context. We want it to work.
*
* If printk indexing is enabled, _printk() is called from printk_index_wrap.
* Otherwise, printk is simply #defined to _printk.
*
* We try to grab the console_lock. If we succeed, it's easy - we log the
* output and call the console drivers. If we fail to get the semaphore, we
* place the output into the log buffer and return. The current holder of
* the console_sem will notice the new output in console_unlock(); and will
* send it to the consoles before releasing the lock.
*
* One effect of this deferred printing is that code which calls printk() and
* then changes console_loglevel may break. This is because console_loglevel
* is inspected when the actual printing occurs.
*
* See also:
* printf(3)
*
* See the vsnprintf() documentation for format string extensions over C99.
*/
#define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
/include/linux/printk.hprintk macro
1
#define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)

附录

linux kernel doc v5.15
Linux kernel doc How to get printk format specifiers right
printf(3) — Linux manual page