typeof详解及Linux 中list_head 如何使用

本文详细介绍了如何在Linux内核中使用C语言创建自定义的list.h头文件,并通过示例展示了如何实现链表的初始化、插入、遍历和删除操作。同时,还提供了一个简单的应用程序示例,演示了如何在应用程序中使用类似内核模块的链表操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp">#include <linux/module.h>
#include <linux/init.h>
#include<linux/sched.h>
#include<linux/sem.h>
#include <linux/slab.h>
#include <linux/list.h>

MODULE_LICENSE("Dual BSD/GPL");

struct group{
    int id;
    char character;
    struct    list_head member;
}; 


int list_head_init(void)
{
    printk("list_head init\n");

    struct  group testhead={
    .id=-1,
    .character='a',
    .member=LIST_HEAD_INIT(testhead.member),
    };
    
     //插入10个元素
    int i=0;
    for(i=0;i<10;i++)                            
    {
        struct group *testtemp;
        testtemp=kmalloc(sizeof(struct group),GFP_KERNEL);
        if(testtemp==NULL) return -1;
        testtemp->id=i;
        testtemp->character=(char)(64+i);
        list_add(&testtemp->member,&testhead.member);
         //printk(KERN_ALERT"%d--->%c\n",testtemp->intdata,testtemp->chardata);
    }


    //遍历10个元素    
    //每一次由1个数据项(链表共10个数据项,前后数据项节点由该数据项节点的list_head类型成员member连接起来) 
		//节点的list_head成员member求出该数据项节点的地址,即&member-->(struct group *) ,求出数据项地址,就可使用数据项成员了    
  
    struct group *groups,*p;
          struct list_head *pos;
          int count=0;
          printk(KERN_ALERT"Hello World enter begin:\n");
          groups=&testhead;
    //第一次 pos 为id = 9的数据项成员member的地址&member ,共10次      
          list_for_each(pos,&groups->member)
               {
               //第一次 由&member(id=9数据项成员member地址)计算出id=9数据项的地址,共10次
               p=list_entry(pos, struct group, member);
               count++;
               printk(KERN_ALERT"id is %d---> name %c\n",p->id,p->character);
               }
          printk(KERN_ALERT"the member of group is:%d\n",count);

    //删除元素
    list_del(&p->member);
    count=0;

    //遍历剩余元素
    
    list_for_each(pos,&groups->member)
               {
               p=list_entry(pos, struct group, member);
               count++;
               printk(KERN_ALERT"id is %d---> name %c\n",p->id,p->character);
               }
          printk(KERN_ALERT"the member of group is:%d\n",count);
    
    return 0;
}
static void list_head_exit(void)
{
    printk("list_head exit\n");
}

module_init(list_head_init);
module_exit(list_head_exit);


 
<pre name="code" class="cpp">Makefile:
KERN_DIR = /work/system/linux-2.6.22.6

all:
        make -C $(KERN_DIR) M=`pwd` modules 

clean:
        make -C $(KERN_DIR) M=`pwd` modules clean
        rm -rf modules.order

obj-m   += list_head.o


 

//编译服务器上:
root@book-desktop:/work/xyc_drivers_and_test/testlist# make
make -C /work/system/linux-2.6.22.6 M=`pwd` modules 
make[1]: Entering directory `/work/system/linux-2.6.22.6'
  CC [M]  /work/xyc_drivers_and_test/testlist/list_head.o
/work/xyc_drivers_and_test/testlist/list_head.c: In function `list_head_init':
/work/xyc_drivers_and_test/testlist/list_head.c:25: warning: ISO C90 forbids mixed declarations and code
/work/xyc_drivers_and_test/testlist/list_head.c:42: warning: ISO C90 forbids mixed declarations and code
/work/xyc_drivers_and_test/testlist/list_head.c:42: warning: 'p' might be used uninitialized in this function
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /work/xyc_drivers_and_test/testlist/list_head.mod.o
  LD [M]  /work/xyc_drivers_and_test/testlist/list_head.ko
make[1]: Leaving directory `/work/system/linux-2.6.22.6'
root@book-desktop:/work/xyc_drivers_and_test/testlist# cp list_head.ko /work/nfs_root/xyc_first_fs/
//串口下:
# insmod list_head.ko 
list_head init
Hello World enter begin:
id is 9---> name I
id is 8---> name H
id is 7---> name G
id is 6---> name F
id is 5---> name E
id is 4---> name D
id is 3---> name C
id is 2---> name B
id is 1---> name A
id is 0---> name @
the member of group is:10
id is 9---> name I
id is 8---> name H
id is 7---> name G
id is 6---> name F
id is 5---> name E
id is 4---> name D
id is 3---> name C
id is 2---> name B
id is 1---> name A
the member of group is:9

此测试模块依赖list.h头文件中断宏: LIST_HEAD_INIT  list_for_each list_entry已经函数list_add等等,所以用的编译成内核模块的方式测试他,自己如果想在应用程序中使用list_head 的相应操作(当然应该没人使用了,C++ STL提供了list 用起来貌似更方便), 在应用程序中需要包含自己的 "list.h" 头文件:

点击打开链接


/*
注:这个list.h 是为了配合示例程序而建的,内容来自:linux/include/linux/list.h 和相关文件
*/
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
 
struct list_head {
         struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})


static inline void INIT_LIST_HEAD(struct list_head *list)
{
        list->next = list;
        list->prev = list;
}

static inline void __list_add(struct list_head *new, struct list_head *prev,struct list_head *next)
{
        next->prev = new;
        new->next = next;
        new->prev = prev;
        prev->next = new;
}


static inline void list_add(struct list_head *new, struct list_head *head)
{
        __list_add(new, head, head->next);
}
 
 
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
        next->prev = prev;
        prev->next = next;
}
 
static inline void list_del(struct list_head *entry)
{
        __list_del(entry->prev, entry->next);
        entry->next = NULL;
        entry->prev = NULL;
}


#define prefetch(x) __builtin_prefetch(x)


//注:这里prefetch 是gcc的一个优化,也可以不要
#define list_for_each(pos, head) \
         for (pos = (head)->next; prefetch(pos->next), pos != (head); \
                 pos = pos->next)

#define list_entry(ptr, type, member) \
         container_of(ptr, type, member)

#endif

写了一个简单的应用程序:

#include "list.h" 
#include <stdio.h> 
#include <string.h>


#define MAX_NAME_LEN 32
#define MAX_ID_LEN 10


typedef struct stud
{
    struct list_head list;
    char name[MAX_NAME_LEN];
    char stu_number[MAX_ID_LEN];
}num_n_stu;


int main(void)
{
    struct list_head head;
    num_n_stu stu_1;
    num_n_stu stu_2;
    num_n_stu *entry;


    struct list_head *p;
    INIT_LIST_HEAD(&head);
    strcpy(stu_1.name,"lisi");
    strcpy(stu_1.stu_number,"10000000");


    strcpy(stu_2.name,"zhangsan");
    strcpy(stu_2.stu_number,"10000001");
    list_add(&stu_1.list,&head);
    list_add(&stu_2.list,&head);
    list_del(&stu_2.list);
    list_for_each(p,&head)
    {
        entry=list_entry(p,struct stud,list);
        printf("name: %s\n",entry->name);
        printf("stu_number: %s\n",entry->stu_number);
    }
    list_del(&stu_1.list);
    return 0;
}

在Linux内核中可以使用这个以类似驱动模块的形式加载到内核:(这里就不用使用自定义的list.h了)

#include <linux/list.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

#define MAX_NAME_LEN 32
#define MAX_ID_LEN 10


typedef struct stud
{
    struct list_head list;
    char name[MAX_NAME_LEN];
    char stu_number[MAX_ID_LEN];
}num_n_stu;

static int my_main(void)
{

    struct list_head head;
    num_n_stu stu_1;
    num_n_stu stu_2;
    num_n_stu *entry;

    struct list_head *p;
    INIT_LIST_HEAD(&head);

    strcpy(stu_1.name,"lisi");
    strcpy(stu_1.stu_number,"10000000");

    strcpy(stu_2.name,"zhangsan");
    strcpy(stu_2.stu_number,"10000001");

    list_add(&stu_1.list,&head);
    list_add(&stu_2.list,&head);

    list_del(&stu_2.list);

    list_for_each(p,&head)
    {

        entry=list_entry(p,struct stud,list);

        printk("name: %s\n",entry->name);

        printk("stu_number: %s\n",entry->stu_number);

    }
    
    list_del(&stu_1.list);
    
    return 0;

}

static void my_exit(void)
{
    printk("my_exit ! \n");
}


module_init(my_main);
module_exit(my_exit);


 C语言typeof详解

操作系统:ubuntu10.04

前言:
    typeof关键字是C语言中的一个新扩展(非c89 c99关键字),这个特性在linux内核中应用非常广泛。

一,说明
    typeof的参数可以是两种形式:表达式类型

    1,表达式的的例子:
        typeof(x[0](1))
        这里假设x是一个函数指针数组,这样就可以得到这个函数返回值的类型了。
        如果将typeof用于表达式,则该表达式不会执行。只会得到该表达式的类型。
        以下示例声明了int类型的var变量,因为表达式foo()是int类型的。由于表达式不会被执行,所以不会调用foo函数。
            extern int foo();
            typeof(foo()) var;

    2,参数的例子:
        typeof(int *) a,b;
            等价于:
            int *a,*b;

下面是两个等效声明,用于声明int类型的变量a。
   typeof(int) a; /*int类型*/
   typeof('b') a; /* GCC中这个表达式的类型是int(自动提升为int),
                  注意typeof(char)和typeof('b')得到的不是一样的,这个用sizeof可以看出来*/

测试:

typeof.c:

#include<stdio.h>
int main()
{
        typeof(int) a;
        typeof('c') b;
        printf("sizeof(a) = %d, sizeof(b) =%d\n", sizeof(a), sizeof(b));
        return 0;
}

root@book-desktop:/work/xyc_drivers_and_test# cc typeof.c 
root@book-desktop:/work/xyc_drivers_and_test# ./a.out 
sizeof(a) = 4, sizeof(b) =4

一般情况下用typeof就可以了,但是如果要于ISO C兼容的话,最好是用双下划线的形式:__typeof__。
typeof和typedef很像,事实上,只要能用typedef的地方就可以用typeof。



二,实例
    1,把y定义成x指向的数据类型:
           typeof(*x) y;
    2,把y定义成x指向数据类型的数组:
           typeof(*x) y[4];
    3,把y定义成一个字符指针数组:
            typeof(typeof(char *)[4] ) y;
    这与下面的定义等价:
            char *y[4];
char *y[4]换一种定义形式:
    #define pointer(T) typeof(T *)
  #define array(T,N) typeof(T [N])
    array (pointer(char),4) y;
如果想把T定义成一个表达式的类型,则我们仅仅用typedef无法做到
但可以通过typeof做到:
   typdef typeof(expr) T;


    4, typeof(int *) p1,p2; /* Declares two int pointers p1, p2 */
            int *p1, *p2;

    5, typeof(int) *p3,p4;/* Declares int pointer p3 and int p4 */
            int *p3, p4;

    6, typeof(int [10]) a1, a2;/* Declares two arrays of integers */
            int a1[10], a2[10];


,局限
    typeof构造中的类型名 不能 包含存储类说明符,如 extern static 。不过允许包含类型限定符,如 const volatile
    例如,下列代码是无效的,因为它在typeof构造中声明了extern:
        typeof(extern int) a;

   下列代码使用外部链接来声明标识符b是有效的,表示一个int类型的对象。下一个声明也是有效的,它声明了一个使用const限定符的char类型指针,    表示指针p不能被修改。
 extern typeof(int) b;
 typeof(char * const) p = "a";


四,文件参考
    1,http://blog.youkuaiyun.com/wslong/article/details/7728811
    2,https://gcc.gnu.org/onlinedocs/gcc/Typeof.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值