printk的用法

内核通过 printk() 输出的信息具有日志级别,日志级别是通过在 printk() 输出的字符串前加一个带尖括号的整数来控制的,如 printk("<6>Hello, world!\n");。内核中共提供了八种不同的日志级别,在 linux/kernel.h 中有相应的宏对应。

#define KERN_EMERG "<0>" / system is unusable /
#define KERN_ALERT "<1>" / action must be taken immediately /
#define KERN_CRIT "<2>" / critical conditions /
#define KERN_ERR "<3>" / error conditions /
#define KERN_WARNING "<4>" / warning conditions /
#define KERN_NOTICE "<5>" / normal but significant /
#define KERN_INFO "<6>" / informational /
#define KERN_DEBUG "<7>" / debug-level messages /

所以 printk() 可以这样用:printk(KERN_INFO "Hello, world!\n");。

未指定日志级别的 printk() 采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在 kernel/printk.c 中被定义为整数 4,即对应KERN_WARNING。

在 /proc/sys/kernel/printk 会显示4个数值(可由 echo 修改),分别表示当前控制台日志级别、未明确指定日志级别的默认消息日志级别、最小(最高)允许设置的控制台日志级别、引导时默认的日志级别。当 printk() 中的消息日志级别小于当前控制台日志级别时,printk 的信息(要有\n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过 /proc/kmsg (或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk 的信息也会追加到 /var/log/messages.log 中。

char myname[] = "chinacodec\n";
printk(KERN_INFO "Hello, world %s!\n", myname);

printk

4.2.1. printk函数

    We used the printk function in earlier chapters with the simplifying assumption that it works like printf. Now it's time to introduce some of the differences. 

    我们在前面章节中简单地把printk当作printf函数来使用。现在是时候来介绍它的一些不同之处了。 

    One of the differences is that printk lets you classify messages according to their severity by associating different loglevels, or priorities, with the messages. You usually indicate the loglevel with a macro. For example, KERN_INFO, which we saw prepended to some of the earlier print statements, is one of the possible loglevels of the message. The loglevel macro expands to a string, which is concatenated to the message text at compile time; that's why there is no comma between the priority and the format string in the following examples. Here are two examples of printk commands, a debug message and a critical message: 

    其中一个不同点是,printk允许你按照相关的记录级或优先级将消息严格分类。通常你需要一个宏来指定记录等级。例如,KERN_INFO,我们在早先的的例子中看到过这个宏,它就是消息记录等级的一种。记录等级宏的作用是扩展为一个字符串,这个字符串会在编译期间与相应的消息文本相连接;这就解释了下面例子中为什么在优先级和格式化字符串之间没有逗号了。下面是两个printk函数的例子,一个是调试消息,一个是临界消息: 

printk(KERNDEBUG "Here I am: %s:%i\n", FILE , LINE _);

printk(KERN_CRIT "I'm trashed; giving up on %p\n", ptr);

    There are eight possible loglevel strings, defined in the header ; we list them in order of decreasing severity: 

    在头文件中共定义了八个可用的记录级;我们下面按其严重性倒序列出: 

KERN_EMERG
Used for emergency messages, usually those that precede a crash.
用于突发性事件的消息,通常在系统崩溃之前报告此类消息。
KERN_ALERT
A situation requiring immediate action.
在需要立即操作的情况下使用此消息。
KERN_CRIT
Critical conditions, often related to serious hardware or software failures.
用于临界条件下,通常遇到严重的硬软件错误时使用此消息。
KERN_ERR
Used to report error conditions; device drivers often use KERN_ERR to report hardware difficulties.
用于报告错误条件;设备驱动经常使用KERN_ERR报告硬件难题。
KERN_WARNING
Warnings about problematic situations that do not, in themselves, create serious problems with the system.
是关于问题状况的警告,一般这些状况不会引起系统的严重问题。
KERN_NOTICE
Situations that are normal, but still worthy of note. A number of security-related conditions are reported at this level.
该级别较为普通,但仍然值得注意。许多与安全性相关的情况会在这个级别被报告。
KERN_INFO
Informational messages. Many drivers print information about the hardware they find at startup time at this level.
信息消息。许多驱动程序在启动时刻用它来输出获得的硬件信息。

KERN_DEBUG

Used for debugging messages.

用于输出调试信息

    Each string (in the macro expansion) represents an integer in angle brackets. Integers range from 0 to 7, with smaller values representing higher priorities. 

    每一个字符串(由宏扩展而成)表示了尖括号内的一个整数。数值范围从0到7,数值越小,优先级越高。 

    A printk statement with no specified priority defaults to DEFAULT_MESSAGE_LOGLEVEL, specified in kernel/printk.c as an integer. In the 2.6.10 kernel, DEFAULT_MESSAGE_LOGLEVEL is KERN_WARNING, but that has been known to change in the past. 

    一个printk的缺省优先级是DEFAULT_MESSAGE_LOGLEVEL,它是一个在kernel/printk.c文件中指定的整数。在 2.6.10内核中,DEFAULT_MESSAGE_LOGLEVEL相当于KERN_WARNING,但据说在早期版本中这是两个不同的优先级。 

    Based on the loglevel, the kernel may print the message to the current console, be it a text-mode terminal, a serial port, or a parallel printer. If the priority is less than the integer variable console_loglevel, the message is delivered to the console one line at a time (nothing is sent unless a trailing newline is provided). If both klogd and syslogd are running on the system, kernel messages are appended to /var/log/messages (or otherwise treated depending on your syslogd configuration), independent of console_loglevel. If klogd is not running, the message won't reach user space unless you read /proc/kmsg (which is often most easily done with the dmesg command). When using klogd, you should remember that it doesn't save consecutive identical lines; it only saves the first such line and, at a later time, the number of repetitions it received. 

    基于这些记录级,内核可以把消息输出到当前的控制台,也可以是一个文本模式的终端,一个串口,或是一个并口打印机。如果优先级小于×××变量 console_loglevel,那么一次将会只发送一行消息到控制台中(除非遇到一个换行符,否则将什么都不会发送)。如果系统中运行了klogd和syslogd进程,那么内核消息就会被完整地添加到/var/log/messages文件中(或者根据你的syslogd进程的配置状况进行发送)而忽略console_loglevel,如果klogd没有运行,那么消息将不会到达用户空间,除非你对/proc/kmsg文件读取(实际上这项工作已被较早的dmesg命令完成)。当使用klogd时,你应该记住它不会保留重复的消息行;对于它接收到的重复消息,它只会保留第一条。 

    The variable console_loglevel is initialized to DEFAULT_CONSOLE_LOGLEVEL and can be modified through the sys_syslog system call. One way to change it is by specifying the -c switch when invoking klogd, as specified in the klogd manpage. Note that to change the current value, you must first kill klogd and then restart it with the -c option. Alternatively, you can write a program to change the console loglevel. You'll find a version of such a program in misc-progs/setlevel.c in the source files provided on O'Reilly's FTP site. The new level is specified as an integer value between 1 and 8, inclusive. If it is set to 1, only messages of level 0 (KERN_EMERG) reach the console; if it is set to 8, all messages, including debugging ones, are displayed. 

    被初始化为DEFAULT_CONSOLE_LOGLEVEL的console_loglevel变量可以通过sys_syslog系统调用修改。改变它内容的一个方法就是在调用klogd时使用-c选项,具体参考klogd的man帮助。请注意,为了改变当前的数值,你必须首先结束klogd进程,并且用-c选项重新启动它。另一种方法是,你可以写一个应用程序来改变控制台的记录等级。你可以在O'Reilly的FTP站点提供的源代码文件中找到/misc-progs/setlevel.c文件,其中就有一个这样的程序。新记录级为一个1到8的整数。如果设置为1,那么只有优先级为0(KERN_EMERG)的消息才可以到达控制台;如果等级设置为8,那么包括调试信息在内的所有消息都会被显示。 

    It is also possible to read and modify the console loglevel using the text file /proc/sys/kernel/printk. The file hosts four integer values: the current loglevel, the default level for messages that lack an explicit loglevel, the minimum allowed loglevel, and the boot-time default loglevel. Writing a single value to this file changes the current loglevel to that value; thus, for example, you can cause all kernel messages to appear at the console by simply entering: 

    也可以通过文本文件/proc/sys/kernel/printk来获取和更改控制台的记录等级。这个文件中存储着四个整型数值:当前记录级,缺省记录级,最低记录级和启动时刻的缺省记录级。可以向该文件写入一个单一数值来改变当前记录级;例如,如果你可以想所有的内核消息都可以在控制台中显示,可以使用以下命令: 

echo 8 > /proc/sys/kernel/printk

    It should now be apparent why the hello.c sample had the KERN_ALERT; markers; they are there to make sure that the messages appear on the console. 

    现在你应该明白在hello.c示例代码中为什么会有KERN_ALERT;标识了吧;这样做可以保证消息顺利地输出到控制台中 。

printf()函数是格式输出函数,请求printf()打印变量的指令取决与变量的类型.例如,在打印整数是使用%d符号,在打印字符是用%c 符号.这些符号被称为转换说明.因为它们指定了如何不数据转换成可显示的形式.下列列出的是ANSI C标准peintf()提供的各种转换说明.

          转换说明及作为结果的打印输出

%a 浮点数、十六进制数字和p-记数法(C99)

%A    浮点数、十六进制数字和p-记法(C99)

%c    一个字符 

%d    有符号十进制整数 

%e    浮点数、e-记数法

%E    浮点数、E-记数法

%f    浮点数、十进制记数法  

%g    根据数值不同自动选择%f或%e.

%G    根据数值不同自动选择%f或%e.

%i 有符号十进制数(与%d相同)

%o    无符号八进制整数

%p    指针    

%s    字符串

%u    无符号十进制整数

%x    使用十六进制数字0f的无符号十六进制整数 

%X    使用十六进制数字0f的无符号十六进制整数

%%    打印一个百分号

使用printf ()函数

 printf()的基本形式: printf("格式控制字符串",变量列表);

#include<cstdio>

int main()

{

//for int

int i=30122121;

long i2=309095024l;

short i3=30;

unsigned i4=2123453;

printf("%d,%o,%x,%X,%ld,%hd,%u\n",i,i,i,i,i2,i3,i4);//如果是:%l,%h,则输不出结果 

printf("%d,%ld\n",i,i2);//试验不出%ld和%d之间的差别,因为long是4bytes

printf("%hd,%hd\n\n\n",i,i3);//试验了%hd和%d之间的差别,因为short是2bytes

//for string and char

char ch1='d';

unsigned char ch2=160;

char *str="Hello everyone!";

printf("%c,%u,%s\n\n\n",ch1,ch2,str);//unsigned char超过128的没有字符对应

//for float and double,unsigned and signed can not be used with double and float

float fl=2.566545445F;//or 2.566545445f

double dl=265.5651445;

long double dl2=2.5654441454;

//%g没有e格式,默认6位包括小数点前面的数,

//%f没有e格式,默认6位仅只小数点后面包含6位

//%e采用e格式,默认6位为转化后的小数点后面的6位

printf("%f,%e,%g,%.7f\n",fl,dl,dl,dl);

printf("%f,%E,%G,%f\n",fl,dl,dl,dl);//%F is wrong

printf("%.8f,%.10e\n",fl,dl);

printf("%.8e,%.10f\n\n\n",fl,dl);

//for point 

int *iP=&i;

char *iP1=new char;

void *iP2;//dangerous!

printf("%p,%p,%p\n\n\n",iP,iP1,iP2);

//其他知识:负号,表示左对齐(默认是右对齐);%6.3,6表示宽度,3表示精度

char *s="Hello world!";

printf(":%s: \n:%10s: \n:%.10s: \n:%-10s: \n:%.15s: \n:%-15s: \n:%15.10s: \n:%-15.10s:\n\n\n",

    s,s,s,s,s,s,s,s);

double ddd=563.908556444;

printf(":%g: \n:%10g: \n:%.10g: \n:%-10g: \n:%.15g: \n:%-15g: \n:%15.10g: \n:%-15.10g:\n\n\n",

    ddd,ddd,ddd,ddd,ddd,ddd,ddd,ddd);

//还有一个特殊的格式%*.* ,这两个星号的值分别由第二个和第三个参数的值指定

printf("%.*s \n", 8, "abcdefgggggg");

printf("%*.*f   \n", 3,3, 1.25456f);

return 0;

}

------Solutions------
^_^,我来接分了,
d,lx,ld,,lu,这几个都是输出32位的
hd,hx,hu,这几个都是输出16位数据的,
hhd,hhx,hhu,这几个都是输出8位的,
lld,ll,llu,llx,这几个都是输出64位的,

你要的应该是printf("%lld",.....)//10进制
%llu,//16进制
------Solutions------
更正%llu 是64位无符号
%llx才是64位16进制数
------Solutions------