一些常用的函数 宏

    技术2025-12-31  2

    <!-- @page { margin: 2cm } P { margin-bottom: 0cm } P.western { font-size: 10pt } P.cjk { font-size: 10pt } H1 { margin-bottom: 0.21cm } H1.western { font-family: "Arial", sans-serif; font-size: 16pt } H1.cjk { font-family: "文鼎PL简中楷"; font-size: 16pt } H1.ctl { font-family: "文鼎PL简中楷"; font-size: 16pt } -->

    内核相关: kthread_create kthread_run kthread_stop Asmlinkage HZ tick and jiffie BUG( ) BUG_ON( ) shmat

    c相关: <!-- @page { margin: 2cm } P { margin-bottom: 0cm } P.western { font-size: 10pt } P.cjk { font-size: 10pt } H1 { margin-bottom: 0.21cm } H1.western { font-family: "Arial", sans-serif; font-size: 16pt } H1.cjk { font-family: "文鼎PL简中楷"; font-size: 16pt } H1.ctl { font-family: "文鼎PL简中楷"; font-size: 16pt } TD P { margin-bottom: 0cm } A:link { so-language: zxx } -->  memchr strncmp sscanf Sprintf isspace

    <!-- @page { margin: 2cm } P { margin-bottom: 0cm } P.western { font-size: 10pt } P.cjk { font-size: 10pt } H1 { margin-bottom: 0.21cm } H1.western { font-family: "Arial", sans-serif; font-size: 16pt } H1.cjk { font-family: "文鼎PL简中楷"; font-size: 16pt } H1.ctl { font-family: "文鼎PL简中楷"; font-size: 16pt } -->

    kthread_create

    使用kthread_create 创建线程: struct task_struct *kthread_create(int (*threadfn)(void *data),

    void *data, const char *namefmt, ...); 这个函数可以像printk 一样传入某种格式的线程名 线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct 指针传给wake_up_process() ,然后通过此函数运行线程。

    kthread_run

    当然,还有一个创建并启动线程的函数:kthread_run struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char *namefmt, ...);

    kthread_stop

    线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit 函数,或者其他的进程调用kthread_stop 函数,结束线程的运行。 int kthread_stop(struct task_struct *thread); kthread_stop() 通过发送信号给线程。 如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。

    在执行kthread_stop 的时候,目标线程必须没有退出,否则会Oops 。原因很容易理解,当目标线程退出的时候,其对应的task 结构也变得无 效,kthread_stop 引用该无效task 结构就会出错。

     

    Asmlinkage

    看一下 /usr/include/asm/linkage.h 里面的定义: #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) __attribute__ 是关键字,是 gcc C 语言 扩展, regparm(0) 表示不从寄存器传递参数

    如果是 __attribute__((regparm(3))) ,那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从 寄存器取参数。

    如: asmlinkage long sys_sync(void);

     

    HZ, tick and jiffie

    linux 核心每隔固定遧期會發出 timer interrupt (irq 0) hz 是用來定義每一秒有幾次 timer interrupts

    tick hz 的倒數,意即 timer interrupt 每發生一次中斷的時間。如 hz 250 時, tick 4 毫秒 (millisecond)

    jiffies linux 核心變數 (unsigned long) ,它被用來紀錄系統自開幾以來,已經過多少的 tick

    BUG( ) BUG_ON( )

    作用:一些内核调用可以用来方便标记 bug ,提供断言并输出信息。最常用的 两个是 BUG() BUG_ON() 。当被调用的时候,它们会引发 oops ,导致栈的回溯和错误信息的打印。为什么这些声明会导致 oops 跟硬件的体系结构是相关的。大部分体系结构把 BUG() BUG_ON() 定义成某种非法操作,这样自然会产生需要的 oops 。你可以把这些调用当作断言使用,想要断言某种情况不该发生 : if (bad_thing) BUG(); 或者使用更好的形式: BUG_ON(bad_thing);

    可以用 panic() 引发更严重的错误。调用 panic() 不但会打印错误 消息而且还会挂起整个系统。显然,你只应该在极端恶劣的情况下使用它: if (terrible_thing) panic("foo is %ld/n", foo);

    有些时候,你只是需要在终端上打印一下栈的回溯信息来帮助你测试。此时可 以使用 dump_stack() 。它只在终端上打印寄存器上下文和函数的跟踪线索: if (!debug_check) { printk(KERN_DEBUG "provide some information.../n"); dump_stack(); } from:http://www.lupaworld.com/bbs/thread-36983-1-8.html

     

    A lots of places in linux kernel we encounter the macro BUG_ON. BUG_ON macro first checks for the condition and if condition is true then it calls BUG which do a printk of msg and call panic which halts the system.( 如果 BUG_ON 中的条件为真就调用 BUG ,它输出一些信息,然后调用 panic 函数挂起系统。 )

    The unlikely in BUG_ON macro is compiler directive which ask compiler to generate assembly such that the condition mentioned in unlikely isn't going to be met most-of-the time , which reduces jumps and speeds-up things, although if condition mentioned in unlikely met then there will be a long jump and speed will be effected, so must be used carefully. Same is with likely as it is the opposite of unlikely . (据说 likely 一般是很少用的)

     

    shmat

    作用 : 共享内存区对象映射到调用进程的地址空间

      核心处理函数: void *shmat( int shmid , char *shmaddr , int shmflag );shmat() 是用来允许本进程访问一块共享内存的函数。

       int shmid 是那块共享内存的 ID

       char *shmaddr 是共享内存的起始地址

       int shmflag 是本进程对该内存的操作模式。如果是 SHM_RDONLY 的话,就是只读模式。其它的是读写模式

      成功时,这个函数返回共享内存的起始地址。失败时返回 -1

      最近用到内存共享,收集整理了些资料,做了个简单的对比

    memchr

    原型: extern void *memchr(void *buf, char ch, unsigned count);

      头文件: #include <string.h>

      功能:从 buf 所指内存区域的前 count 个字节查找字符 ch

      说明:当第一次遇到字符 ch 时停止查找。如果成功,返回指向字符 ch 的指针;否则返回 NULL

    strncmp

    原型: extern int strcmp(char *s1,char * s2 int n);

    头文件: #include <string.h>

    功能:比较字符串 s1 s2 的前 n 个字符。

    说明:

    s1<s2 时,返回值 <0

    s1=s2 时,返回值 =0

    s1>s2 时,返回值 >0

    sscanf

    函数原型 :

      Int sscanf( const char *, const char *, ...);

      int scanf( const char *, ...);

      头文件: #include<stdio.h>

       1. 常见用法。

       char buf[512] = ;

       sscanf("123456 ", "%s", buf);// 此处 buf 是数组名,它的意思是将 123465 %s 的形式存入 buf 中!

    返回值:有多少个变量被赋值。 int n= sscanf(str,"%2d%2d",&x,&y);

    Sprintf

    函数原型 :

    #include <stdio.h>

    int sprintf(char *string, char *farmat [,argument,...]);

    详细描述 : 函数 sprin tf() 的用法和printf() 函数一样,只是 sprintf 的作用是将一个格式化的字符串输出到一个目的字 符串中,而 printf 是将一个格式化的字符串输出到屏幕。

      例如: sprintf(s, "%d", 123); // 把整数 123 打印成一个字符串保存在 s 中。

    返回值: 返回本次函数调用打印到字符缓冲区中的字符数目

    isspace

       #include<ctype.h >

      定义函数

       int isspace(int c)

      函数说明 : 检查参数 c 是否为空格字符,也就是判断是否为空格 ('') 、定位字符 ('/t') CR('/r') 、换行 ('/n') 、垂直定位字符 ('/v') 或翻页 (' /f') 的情况。

      返回值 : 若参数 c 为空格字符,则返回 TRUE ,否则返回 NULL(0)

      附加说明 :  此为宏定义,非真正函数。

     

    基本 C 库函数

    当编写驱动程序时,一般情况下不能使用C 标准库的函数。Linux 内核也提供了与标准库函数功能相同的一些函数,但二者还是稍有差别。

    类别

    函数名

    功能

    函数形成

    参数

    描述

    字符串转换

    simple_strtol

    把一个字符串转换为一个有符号长整数

    long simple_strtol (const char * cp, char ** endp, unsigned int base)

    cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。

     

    simple_strtoll

    把一个字符串转换为一个有符号长长整数

    long long simple_strtoll (const char * cp, char ** endp, unsigned int base)

    cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。

     

    simple_strtoul

    把一个字符串转换为一个无符号长整数

    long long simple_strtoul (const char * cp, char ** endp, unsigned int base)

    cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。

     

    simple_strtoull

    把一个字符串转换为一个无符号长长整数

    long long simple_strtoull (const char * cp, char ** endp, unsigned int base)

    cp 指向字符串的开始,endp 为指向要分析的字符串末尾处的位置,base 为要用的基数。

     

    vsnprintf

    格式化一个字符串,并把它放在缓存中。

    int vsnprintf (char * buf, size_t size, const char * fmt, va_list args)

    buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为要使用的格式化字符串,args 为格式化字符串的参数。

     

    snprintf

    格式化一个字符串,并把它放在缓存中。

    int snprintf (char * buf, size_t size, const char * fmt, ... ...)

    buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为格式化字符串,使用@… 来对格式化字符串进行格式化,…为可变参数。

     

    vsprintf

    格式化一个字符串,并把它放在缓存中。

    int vsprintf (char * buf, const char * fmt, va_list args)

    buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为要使用的格式化字符串,args 为格式化字符串的参数。

     

    sprintf

    格式化一个字符串,并把它放在缓存中。

    int sprintf (char * buf, const char * fmt, ... ...)

    buf 为存放结果的缓冲区, size 为缓冲区的大小,fmt 为格式化字符串,使用@… 来对格式化字符串进行格式化,…为可变参数。

     

    字符串操作

    strcpy

    拷贝一个以NUL 结束的字符串

    char * strcpy (char * dest, const char * src)

    dest 为目的字符串的位置, src 为源字符串的位置。

     

    strncpy

    拷贝一个定长的、以NUL 结束的字符串

    char * strncpy (char * dest, const char * src, size_t count)

    dest 为目的字符串的位置, src 为源字符串的位置,count 为要拷贝的最大字节数

    与用户空间的strncpy 不同,这个函数并不用NUL 填充缓冲区,如果与源串超过count ,则结果以非NUL 结束

    strcat

    把一个以NUL 结束的字符串添加到另一个串的末尾

    char * strcat (char * dest, const char * src)

    dest 为要添加的字符串, src 为源字符串。

     

    strncat

    把一个定长的、以NUL 结束的字符串添加到另一个串的末尾

    char * strncat (char * dest, const char * src, size_t count)

    dest 为要添加的字符串, src 为源字符串,count 为要拷贝的最大字节数

    注意,与strncpy, 形成对照, strncat 正常结束。

    strchr

    在一个字符串中查找第一次出现的某个字 符

    char * strchr (const char * s, int c)

    s 为被搜索的字符串,c 为待搜索的字符。

     

    strrchr

    在一个字符串中查找最后一次出现的某个 字符

    char * strrchr (const char * s, int c)

    s 为被搜索的字符串,c 为待搜索的字符。

     

    strlen

    给出一个字符串的长度

    size_t strlen (const char * s)

    s 为给定的字符串

     

    strnlen

    给出给定长度字符串的长度

    size_t strnlen (const char * s, size_t count)

    s 为给定的字符串

     

    strpbrk

    在一个字符串中查找第一次出现的一组字 符

    char * strpbrk (const char * cs, const char * ct)

    cs 为被搜索的字符串,ct 为待搜索的一组字符

     

    strtok

    把一个字符串分割为子串

    char * strtok (char * s, const char * ct)

    s 为被搜索的字符串,ct 为待搜索的子串

    注意,一般不提倡用这个函数,而应当用strsep

    memset

    用给定的值填充内存区

    void * memset (void * s, int c, size_t count)

    s 为指向内存区起始的指针,c 为 要填充的内 容,count 为 内存区的大小

    I/O 空间的访问不能使用memset ,而应当使用memset_io

    bcopy

    把内存的一个区域拷贝到另一个区域

    char * bcopy (const char * src, char * dest, int count)

    src 为源字符串,dest 为目的字符串,而count 为内存区的大小

    注意,这个函数的功能与memcpy 相同,这是从BSD 遗留下来的,对I/O 空间的访问应当用memcpy_toio memcpy_fromio

    memcpy

    把内存的一个区域拷贝到另一个区域

    void * memcpy (void * dest, const void * src, size_t count)

    dest 为目的字符串,Src 为源字符串,而count 为内存区的大小

    I/O 空间的访问应当用memcpy_toio memcpy_fromio

    memmove

    把内存的一个区域拷贝到另一个区域

    void * memmove (void * dest, const void * src, size_t count)

    dest 为目的字符串,Src 为源字符串,而count 为内存区的大小

    memcpy memmove 处理重叠的区域,而该函数不处理。

    memcmp

    比较内存的两个区域

    int memcmp (const void * cs, const void * ct, size_t count)

    cs 为一个内存区,ct 为另一个内存区,而count 为内存区的大小

     

    memscan

    在一个内存区中查找一个字符

    void * memscan (void * addr, int c, size_t size)

    addr 为内存区,c 为要搜索的字符,而size 为内存区的大小

    返回c 第一次出现的地址,如果没有找到c ,则向该内存区传递一个字节。

    strstr

    在以NUL 结束的串中查找第一个出现的子串

    char * strstr (const char * s1, const char * s2)

    s1 为被搜索的串,s2 为待搜索的串。

     

    memchr

    在一个内存区中查找一个字符

    void * memchr (const void * s, int c, size_t n)

    s 为内存区,为待搜索的字符,n 为内存的大小

    返回c 第一次出现的位置,如果没有找到c ,则返回空。

    位操作

    set_bit

    在位图中原子地设置某一位

    void set_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址

    这个函数是原子操作,如果不需要原子操 作,则调用__set_bit 函数,nr 可以任意大,位图的大小不限于一个字。

    __set_bit

    在位图中设置某一位

    void __set_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址

     

    clear_bit

    在位图中清某一位

    void clear_bit (int nr, volatile void * addr)

    nr 为要清的位,addr 为位图的起始地址

    该函数是原子操作,但不具有加锁功能, 如果要用于加锁目的,应当调用smp_mb__before_clear_bit smp_mb__after_clear_bit 函数,以确保任何改变在其他的处理器上是可见的。

    __change_bit

    在位图中改变某一位

    void __change_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址。

    change_bit 不同,该函数是非原子操 作。

    change_bit

    在位图中改变某一位

    void change_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址。

     

    test_and_set_bit

    设置某一位并返回该位原来的值

    int test_and_set_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址。

    该函数是原子操作

     __test_and_set_bit

    设置某一位并返回该位原来的值

    int __test_and_set_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址。

    该函数是非原子操作,如果这个操作的两 个实例发生竞争,则一个成功而另一个失败,因此应当用一个锁来保护对某一位的多个访问。

     test_and_clear_bit

    清某一位,并返回原来的值

    int test_and_clear_bit (int nr, volatile void * addr);

    nr 为要设置的位,addr 为位图的起始地址。

    该函数是原子操作

    __test_and_clear_bit

    清某一位,并返回原来的值

    int __test_and_clear_bit (int nr, volatile void * addr);

    nr 为要设置的位,addr 为位图的起始地址。

    该函数为非原子操作

    test_and_change_bit

    改变某一位并返回该位的新值

    int test_and_change_bit (int nr, volatile void * addr)

    nr 为要设置的位,addr 为位图的起始地址。

    该函数为原子操作

    test_bit

    确定某位是否被设置

    int test_bit (int nr, const volatile void * addr)

    nr 为要测试的第几位,addr 为位图的起始地址。

     

     find_first_zero_bit

    在内存区中查找第一个值为0 的位

    int find_first_zero_bit (void * addr, unsigned size)

    addr 为内存区的起始地址,size 为要查找的最大长度

    返回第一个位为0 的位号

    find_next_zero_bit

    在内存区中查找第一个值为0 的位

    int find_next_zero_bit (void * addr, int size, int offset)

    addr 为内存区的起始地址,size 为要查找的最大长度,offset 开始搜索的起始位号。

     

    ffz

    在字中查找第一个0

    unsigned long ffz (unsigned long word);

    word 为要搜索的字。

     

    ffs

    查找第一个已设置的位

    int ffs (int x)

    x 为要搜索的字。

    这个函数的定义方式与Libc 中的一样。

    hweight32

    返回一个N 位 字的加权平衡值

    hweight32 ( x)

    x 为要加权的字

    一个数的加权平衡是这个数所有位的总和。

     

     

    kthread_create

    使用kthread_create 创建线程: struct task_struct *kthread_create(int (*threadfn)(void *data),

    void *data, const char *namefmt, ...); 这个函数可以像printk 一样传入某种格式的线程名 线程创建后,不会马上运行,而是需要将kthread_create() 返回的task_struct 指针传给wake_up_process() ,然后通过此函数运行线程。

    kthread_run

    当然,还有一个创建并启动线程的函数:kthread_run struct task_struct *kthread_run(int (*threadfn)(void *data), void *data, const char *namefmt, ...);

    kthread_stop

    线程一旦启动起来后,会一直运行,除非该线程主动调用do_exit 函数,或者其他的进程调用kthread_stop 函数,结束线程的运行。 int kthread_stop(struct task_struct *thread); kthread_stop() 通过发送信号给线程。 如果线程函数正在处理一个非常重要的任务,它不会被中断的。当然如果线程函数永远不返回并且不检查信号,它将永远都不会停止。

    在执行kthread_stop 的时候,目标线程必须没有退出,否则会Oops 。原因很容易理解,当目标线程退出的时候,其对应的task 结构也变得无 效,kthread_stop 引用该无效task 结构就会出错。

     

    Asmlinkage

    看一下 /usr/include/asm/linkage.h 里面的定义: #define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0))) __attribute__ 是关键字,是 gcc C 语言 扩展, regparm(0) 表示不从寄存器传递参数

    如果是 __attribute__((regparm(3))) ,那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从 寄存器取参数。

    如: asmlinkage long sys_sync(void);

     

    HZ, tick and jiffie

    linux 核心每隔固定遧期會發出 timer interrupt (irq 0) hz 是用來定義每一秒有幾次 timer interrupts

    tick hz 的倒數,意即 timer interrupt 每發生一次中斷的時間。如 hz 250 時, tick 4 毫秒 (millisecond)

    jiffies linux 核心變數 (unsigned long) ,它被用來紀錄系統自開幾以來,已經過多少的 tick

    BUG( ) BUG_ON( )

    作用:一些内核调用可以用来方便标记 bug ,提供断言并输出信息。最常用的 两个是 BUG() BUG_ON() 。当被调用的时候,它们会引发 oops ,导致栈的回溯和错误信息的打印。为什么这些声明会导致 oops 跟硬件的体系结构是相关的。大部分体系结构把 BUG() BUG_ON() 定义成某种非法操作,这样自然会产生需要的 oops 。你可以把这些调用当作断言使用,想要断言某种情况不该发生 : if (bad_thing) BUG(); 或者使用更好的形式: BUG_ON(bad_thing);

    可以用 panic() 引发更严重的错误。调用 panic() 不但会打印错误 消息而且还会挂起整个系统。显然,你只应该在极端恶劣的情况下使用它: if (terrible_thing) panic("foo is %ld/n", foo);

    有些时候,你只是需要在终端上打印一下栈的回溯信息来帮助你测试。此时可 以使用 dump_stack() 。它只在终端上打印寄存器上下文和函数的跟踪线索: if (!debug_check) { printk(KERN_DEBUG "provide some information.../n"); dump_stack(); } from:http://www.lupaworld.com/bbs/thread-36983-1-8.html

     

    A lots of places in linux kernel we encounter the macro BUG_ON. BUG_ON macro first checks for the condition and if condition is true then it calls BUG which do a printk of msg and call panic which halts the system.( 如果 BUG_ON 中的条件为真就调用 BUG ,它输出一些信息,然后调用 panic 函数挂起系统。 )

    The unlikely in BUG_ON macro is compiler directive which ask compiler to generate assembly such that the condition mentioned in unlikely isn't going to be met most-of-the time , which reduces jumps and speeds-up things, although if condition mentioned in unlikely met then there will be a long jump and speed will be effected, so must be used carefully. Same is with likely as it is the opposite of unlikely . (据说 likely 一般是很少用的)

     

    shmat

    作用 : 共享内存区对象映射到调用进程的地址空间

      核心处理函数: void *shmat( int shmid , char *shmaddr , int shmflag );shmat() 是用来允许本进程访问一块共享内存的函数。

       int shmid 是那块共享内存的 ID

       char *shmaddr 是共享内存的起始地址

       int shmflag 是本进程对该内存的操作模式。如果是 SHM_RDONLY 的话,就是只读模式。其它的是读写模式

      成功时,这个函数返回共享内存的起始地址。失败时返回 -1

      最近用到内存共享,收集整理了些资料,做了个简单的对比

    最新回复(0)