欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C/C++--(5)函数printk/strtok/getline/strtol/sscanf

程序员文章站 2024-01-20 10:42:46
strtok #include #include using namespace std; /* * *--------------------------...

strtok

#include 
#include 

using namespace std;

/* * *--------------------------------- i'm seperator line -----------------------------------
*  定义函数:char * strtok(char *s, const char *delim);
*
*  函数说明:strtok()用来将字符串分割成一个个片段。参数s 指向欲分割的字符串,参数delim 则为分割字符串,
*  当strtok()在参数s 的字符串中发现到参数delim 的分割字符时则会将该字符改为\0 字符。在第一次调用时,
*  strtok()必需给予参数s 字符串,往后的调用则将参数s 设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
*
*  返回值:返回下一个分割后的字符串指针,如果已无从分割则返回NULL。
*/

void main() {
    char s[] = "ab-cd : ef;gh :i-jkl;mnop;qrs-tu:1 vwx-y;z";
    char *delim = "-: ";
    char *p;
    printf("%s ", strtok(s, delim));
    while ((p = strtok(NULL, delim)))
        printf("%s\n", p);
    printf("\n");
}

getline

#include  
#include 

using namespace std;

int main(){
    string line;
    //在这个语句中,首先getline从标准输入设备上读入字符,然后返回给输入流cin,注意了,
    //是cin,所以while判断语句的真实判断对象是cin,也就是判断当前是否存在有效的输入流.
    //while(getline(cin,line))//这里默认回车符停止读入,按Ctrl+Z回车即可退出循环
        //cout<strtol,sscanf
#include 
#include 
#include   
#include 

using namespace std;


//十六进制字符串转数字(数值)主要有两个方法,其实都是对现有函数的使用:

/* * *--------------------------------i'm seperator line -------------------------------
 *  方法1: sscanf()
 *
 *  function name: sscanf 
 *  功  能: 从字符串格式化输入 
 *  用  法: int sscanf(char *string, char *format[,argument,...]);format 为 %x 就是将字符串格式化为 16 进制数
 */
void method1(){
    //char* p = "0x12";  //用于测试16进制
    char* p = "11";      
    int nValude = 0;          
    sscanf(p, "%x", &nValude);      
    printf("%d\r\n", nValude);  

    sscanf(p, "%o", &nValude);      
    printf("%d\r\n", nValude);  

    sscanf(p, "%d", &nValude);      
    printf("%d\r\n", nValude);  
}

/* * *-----------------------------i'm seperator line ------------------------------
 *  方法2: strtol()
 *  
 *  函数名: strtol 
 *  功  能: 将字符串转换为长整数 
 *  用  法: long strtol(char *str, char **endptr, int base);base就是我们要转换为几进制数
 */
void method2(){
    //char* p = "0x12";  //用于测试16进制
    char* p = "12";  
    char* str;      
    long i = strtol(p, &str, 16);
    printf("%d\r\n", i);

    i = strtol(p, &str, 8);
    printf("%d\r\n", i);

    i = strtol(p, &str, 10);
    printf("%d\r\n", i);
}

void main()   {   
    method1();
    method2();
} 

printk

–查看当前控制台的打印级别

  cat /proc/sys/kernel/printk
  4    4    1    7

其中第一个“4”表示内核打印函数printk的打印级别,只有级别比他高的信息才能在控制台上打印出来,既 0-3级别的信息
–修改打印

echo "新的打印级别  4    1    7" >/proc/sys/kernel/printk

printk相当于printf的孪生姐妹,她们一个运行在用户态,另一个则在内核态被人们所熟知。
printk与printf有差异,是什么导致一个运行在内核态而另一个运行用户态?其实这两个函数的几乎是相同的,出现这种差异是因为tty_write函数
需要使用fs指向的被显示的字符串,而fs是专门用于存放用户态段选择符的,因此,在内核态时,为了配合tty_write函数,printk会把fs修改为内核
态数据段选择符ds中的值,这样才能正确指向内核的数据缓冲区,当然这个操作会先对fs进行压栈保存,调用tty_write完毕后再出栈恢复。总结说
来,printk与printf的差异是由fs造成的,所以差异也是围绕对fs的处理。
在使用printk()函数中使用日志级别为的是使编程人员在编程过程中自定义地进行信息的输出,更加容易地掌握系统当前的状况。
对程序的调试起到了很重要的作用。
下文中的日志级别和控制台日志控制级别是一个意思
语法:printk(日志级别 “消息文本”);这里的日志级别通俗的说指的是对文本信息的一种输出范围上的指定。
日志级别一共有8个级别,printk的日志级别定义如下(在linux26/include/linux/kernel.h中):

    #define KERN_EMERG      "<0>"           /*紧急事件消息,系统崩溃之前提示,表示系统不可用*/
    #define KERN_ALERT      "<1>"           /*报告消息,表示必须立即采取措施*/
    #define KERN_CRIT       "<2>"           /*临界条件,通常涉及严重的硬件或软件操作失败*/
    #define KERN_ERR        "<3>"           /*错误条件,驱动程序常用KERN_ERR来报告硬件的错误*/
    #define KERN_WARNING    "<4>"           /*警告条件,对可能出现问题的情况进行警告*/
    #define KERN_NOTICE     "<5>"           /*正常但又重要的条件,用于提醒。常用于与安全相关的消息*/
    #define KERN_INFO       "<6>"           /*提示信息,如驱动程序启动时,打印硬件信息*/
    #define KERN_DEBUG      "<7>"           /*调试级别的消息*/

没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL(这个默认级别一般为<4>,即与KERN_WARNING在一个级别上),
其定义在linux26/kernel/printk.c中可以找到。
下面是一个比较简单的使用

 printk(KERN_INFO "INFO\n");  //这里可以使用数字代替 KERN_INFO,即可以写成printk(<6> "INFO\n");  

在这个格式的定义中,日志级别和信息文本之间不能够使用逗号隔开,因为系统在进行编译的时候,将日志级别转换成字符串于后面的文本信息进行连接。
在对系统输出进行控制时,主要是讨论控制台和伪终端的输情况,以及系统日志等。
下面是控制台日志级别的一些简要的介绍
控制台相应的日志级别定义如下:

#define MINIMUM_CONSOLE_LOGLEVEL  1     /*可以使用的最小日志级别*/
#define DEFAULT_CONSOLE_LOGLEVEL  7         /*比KERN_DEBUG 更重要的消息都被打印*/

int console_printk[4] = {
    DEFAULT_CONSOLE_LOGLEVEL,   /*控制台日志级别,优先级高于该值的消息将在控制台显示*/
    DEFAULT_MESSAGE_LOGLEVEL,   /*默认消息日志级别,printk没定义优先级时,打印这个优先级以上的消息*/
    MINIMUM_CONSOLE_LOGLEVEL,   /*最小控制台日志级别,控制台日志级别可被设置的最小值(最高优先级)*/
    DEFAULT_CONSOLE_LOGLEVEL,   /* 默认的控制台日志级别*/
};

在进行查看的时候,可以使用命令 cat /proc/sys/kernel/printk来查看这四个值
可以通过修改文件/proc/sys/kernel/printk中的第一个值来更改当前的控制台日志级别。
声明:在下面的模块函数中控制台所使用的日志级别均为KERN_WARNING级别
当日志级别高于console_loglevel(控制台日志级别)时,消息才能在控制台显示出来。
假如写了一个如下的模块函数:

#include 
#include 
MODULE_LICENSE("Dual BSD/GPL");
static int book_init(void)
{
    printk(KERN_EMERG "EMERG\n");
    printk(KERN_ALERT "ALERT\n");
    printk(KERN_CRIT " CRIT\n");
    printk(KERN_ERR " ERR\n");
    printk(KERN_WARNING "WARNING\n");
    printk(KERN_NOTICE "NOTICE\n");
    printk(KERN_INFO "INFO\n");
    printk(KERN_DEBUG "DEBUG\n");
    return 0;
}
static void book_exit(void)
{
    printk(KERN_ALERT "Book module exit\n");
}
module_init(book_init);
module_exit(book_exit);

在控制台(这里指的是虚拟终端 Ctrl+Alt+(F1~F6))加载模块以后,控制台给出的信息为6~9行中要求输出的信息,在伪终端(如果对伪终端不是很
清楚可以看相关的内容)上运行命令

tail -n 10 /var/log/messages

查看日志文件刚才得到的运行记录
可以发现messages中的值为KERN_WARNING级别之后所要求输出到信息值。而如果在文件syslog和kern-log中查看系统日志文件,一般情况下可以得到
所有的输出信息

Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637057] INFO
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637063] CRIT
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637066] WARNING
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637068] ERR
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637069] ALERT
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637070] EMERG
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637071]  NOTICE 
Jul 18 11:44:19 xiyoulinux-desktop kernel: [16100.637072] DEBUG

不过在有些机器上运行得到的结果并不是这样的,即一般情况下,syslog和kern.log两个文件中记录的内容从编程这个角度来看是基本一致的。
在目录/var/log/下有一共四个文件可以查看日志,syslog ,kern.log,messages ,DEBUG 。
syslog和kern.log一般情况下可以得到所有的系统输出值,而messages得到的是比控制台日志级别低的输出值,DEBUG得到的仅仅是DEBUG级别的输出值。
一般情况下,优先级高于控制台日志级别的消息将被打印到控制台。优先级低于控制台日志级别的消息将被打印到messages日志文件中,而在伪终端下
不打印任何的信息。 在进行有关编程的时候,若使用到printk()这个函数,一般查看信息是在messages和虚拟终端下进行查看,而对于syslog和kern.log下是用来检验所有信息的输出情况。
/var/log目录下的20个Linux日志文件功能:
–/var/log/messages
包括整体系统信息,其中也包含系统启动期间的日志。此外,mail,cron,daemon,kern和auth等内容也记录
在var/log/messages日志中。
–/var/log/dmesg
包含内核缓冲信息(kernel ring buffer)。在系统启动时,会在屏幕上显示许多与硬件有关的信息。可以用dmesg查看它们。
–/var/log/auth.log
包含系统授权信息,包括用户登录和使用的权限机制等。
–/var/log/boot.log
包含系统启动时的日志。
–/var/log/daemon.log
包含各种系统后台守护进程日志信息。
–/var/log/dpkg.log
包括安装或dpkg命令清除软件包的日志。
–/var/log/kern.log
包含内核产生的日志,有助于在定制内核时解决问题。
–/var/log/lastlog
记录所有用户的最近信息。这不是一个ASCII文件,因此需要用lastlog命令查看内容。
–/var/log/maillog /var/log/mail.log
包含来着系统运行电子邮件服务器的日志信息。例如,sendmail日志信息就全部送到这个文件中。
–/var/log/user.log
记录所有等级用户信息的日志。
–/var/log/Xorg.x.log
来自X的日志信息。
–/var/log/alternatives.log
更新替代信息都记录在这个文件中。
–/var/log/btmp
记录所有失败登录信息。使用last命令可以查看btmp文件。例如,”last -f /var/log/btmp | more“。
–/var/log/cups
涉及所有打印信息的日志。
–/var/log/anaconda.log
在安装Linux时,所有安装信息都储存在这个文件中。
–/var/log/yum.log
包含使用yum安装的软件包信息。
–/var/log/cron
每当cron进程开始一个工作时,就会将相关信息记录在这个文件中。
–/var/log/secure
包含验证和授权方面信息。例如,sshd会将所有信息记录(其中包括失败登录)在这里。
–/var/log/wtmp或/var/log/utmp
包含登录信息。使用wtmp可以找出谁正在登陆进入系统,谁使用命令显示这个文件或信息等。
–/var/log/faillog
包含用户登录失败信息。此外,错误登录命令也会记录在本文件中。

;>;>