作业2Linux kernel部分

本文探讨了C语言中两种宏定义的最大值选择及其优劣对比,分析了特定结构体定义可能引发的问题,并讨论了不同数据类型在内存中的对齐方式及大小。此外,还涉及了如何在Linux内核中实现用户空间到内核空间的数据传递。
1.下面的两个宏,max和DMX_MAX相比,谁更优,原因是什么?
c
#define max(x, y) ({
    typeof(x) _max1 = (x);
    typeof(y) _max2 = (y);
    (void) (&_max1 == &_max2);
    _max1 > _max2 ? _max1 ; _max2; }

#define DMX_MAX(x, y) (((x) > (y)) ? (x) : (y))
max更优,首先当执行x++时,max只需进行一次x运算,因为x赋值给max1了,以下只需对max1进行操作,而DMX则需要进行两次x操作,因为DMX只进行直接替换操作,替换后x还需要进行x++操作。其次,max中的第四行还会检查两个数的类型。

比如#define MAX(a,b) ((a)>(b)?(a):(b))
  则遇到MAX(1+2,value)则会把它替换成:
  ((1+2)>(value)?(1+2):(value))

2.请指出如下struct的定义导致read_dev在执行时可能会发生什么问题?

struct devregs定义了一个用于存储两个寄存器:csr和data的结构体。
read_dev的目的是从设备n中读取一个字节,如果报错,则reset错误,并返回0xffff,如果成功,返回读取的字节值

c
struct devregs {
     Volatile   UINT8 csr;/*加上Volatile关键字*/
     Volatile   UINT8 data; /*加上Volatile关键字*/
};

UINT16 read_dev(UINT16 devno){

        struct devregs * const dvp = DEVADDR + devno;

        while((dvp->csr & (READY | ERROR)) == 0)
                ; /* NULL - wait till done */

        if(dvp->csr & ERROR){
                dvp->csr = RESET;
                return(0xffff);
        }

        return((dvp->data) & 0xff);
}



需要加入Volatile关键字,表示每次从内存中读,而不是从寄存器中读。

int8_t,uint16_t,uint32_t等都不是什么新的数据类型,它们只是使用typedef给类型起的别名,新瓶装老酒的把戏。不过,不要小看了typedef,它对于你代码的维护会有很好的作用。
按照posix标准,一般整形对应的*_t类型为:
1字节 uint8_t
2字节 uint16_t
4字节 uint32_t
8字节 uint64_t
volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据.

3.下面的执行结果是什么?
c
int main(int arg, char *argv[])
{
    char *strTest = “Hello”;
    char aszSample[32];
    char cTmp = ‘A’;
    char *p = NULL;

    printf(“%d, %d\r\n”, sizeof(strTest), sizeof(aszSample));
    printf(“%d, %d, %d\r\n”, sizeof(cTmp), sizeof(p), sizeof(*p));

**运行结果为:8(64位即为8,32位的为4) 32
          1 8(同上解释) 1**

comment:
sizeof是单目运算符,其运算符的含义是:求出对象在计算机内存中所占用的字节数。
指针的sizeof
指针是用来记录另一个对象的地址,所以指针的内存大小当然就等于计算机内部地址总线的宽度。
在32位计算机中,一个指针变量的返回值必定是4。
指针变量的sizeof值与指针所指的对象没有任何关系。

eg:
c
char *b = "helloworld";  
char *c[10];  
double *d;  
int **e;  
void (*pf)();    

cout<<"char *b = /"helloworld/"     "<<sizeof(b)<<endl;//指针指向字符串,值为4  
cout<<"char *b                    "<<sizeof(*b)<<endl; //指针指向字符,值为1  
cout<<"double *d                  "<<sizeof(d)<<endl;//指针,值为4  
cout<<"double *d                  "<<sizeof(*d)<<endl;//指针指向浮点数,值为8  
cout<<"int **e                  "<<sizeof(e)<<endl;//指针指向指针,值为4  
cout<<"char *c[10]                "<<sizeof(c)<<endl;//指针数组,值为40  
cout<<"void (*pf)();              "<<sizeof(pf)<<endl;//函数指针,值为4  
4.64位机中,定义了如下的结构体和变量:
struct MySample {
    u32 size;
    long b;
    u32 elem[7];
    u32 count;
};
struct MySample rSample;
u32 g_elem[7];
**需要考虑字节对齐问题。u32 为无符号的int型是4个字节,本题为64位机,所以需要补4位;long为8个字节,不用补;再为u32,因为为数组所以需要乘以7,为28个字节,再加上后面的4个正好为32个字节,是8的倍数,不用补了。题中的错误的是sizeof(u32)+sizeof(u32)为12个字节,相当于从long的中间开始复制,是不对的,正确的如下:
memcpy((u8 *)(&rSample) + sizeof(u32) + sizeof(u32)+ sizeof(long), g_elem, 7 * sizeof(u32));**

请问如果现在要将g_elem数组中的内容复制到rSample的elem数组中,如果按照如下来做是否正确?
memcpy((u8 )(&rSample) + sizeof(u32) + sizeof(long), g_elem, 7 sizeof(u32));
如果不正确,那要怎么写?

comment:
memcpy可以将结构体拷贝到字符数组中,但直接从字符数组中是不能取出想要的结果的。因为结构体中数据类型和字符类型是不一致的,如果真要取出数据内容,有两种方法:1.再次使用memcpy进行解析 2.强制类型转换.

c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
用法:void *memcpy(void *dest, const void *src, size_t n);
(参数1,参数2,长度);表示参数2复制到参数1中,长度为多少字节。

5.32位机中,定义了如下结构体:
struct student {
    struct student *next;
    char  *name;
    __u32 age;
    long  id;
    __u16 class;
    char  classN[32];   
};
struct studentUsr {
    char  *name;
    __u32 age;
    long  id;
    __u16 class;
    char  classN[32];   
};
struct class{
    __u16 class;
    char  classN[32];
    __u32 count;
    struct student *list;
};

要求在linux kernel中实现如下函数:

int add_student(void __user *arg)

将32bit User Space传递下来的结构体实体(“He Li”, 16, 0002, 0502, “class-05-02”)信息,添加到kernel中已经存在的存储有的班级信息的全局变量数组(struct class g_arClass[5][5])中的对应element中。

例如class为0501的是代表5年级1班,对应的element是g_arClass[4][0];

添加信息后,要打印被成功添加的学生的成员变量信息。

struct student {
                struct student *next;
                char  *name;
                __u32 age;
                long  id;
                __u16 class;
                char  classN[32];               
};
struct studentUsr {
                char  *name;
                __u32 age;
                long  id;
                __u16 class;
                char  classN[32];               
};
struct class{
                __u16 class;
                char  classN[32];
                __u32 count;
                struct student *list; 
};

struct class g_arClass[5][5]  // 存储有的班级信息的全局变量数组

int add_student(void __user *arg)
{
                int ret = 0;
                struct studentUsr rParam;
                struct student  st1;
                int grade , class;

                memset(&rParam, 0, sizeof(rParam));
                if (0 == access_ok(VERIFY_READ | VERIFY_WRITE,(void *arg),sizeof(rPARAM))) {
                                return (–EACCESS);
                }              

                ret =  copy_from_user((void *)&rParam,(void *)arg, sizeof(rParam));
                if (0 != ret) {
                                                /* encounter error */
                                                return (–EACCESS);
                }

                grade= rPARAM.class/100 ;   // get 年级 info
                class= rPARAM.class%100 ;  // get 班级 info

                if(grade>4||class>4)
                                return (–EACCESS);

                memcpy(st1.name,rPARAM.name,strlen(rPARAM.name));
                memcpy(st1.classN,rPARAM.classN,strlen(rPARAM.classN));
                st1.age=rPARAM.age;
                st1.id=rPARAM.age;
                st1.class=rPARAM.class;

                g_arClass[grade-1][class-1].class=st1.class;
                memcpy(g_arClass[grade-1][class-1].classN,rPARAM.classN,strlen(rPARAM.classN));
                g_arClass[grade-1][class-1].list=&st1;

                printk("name is %s, age is %d , classN is %s \n",rPARAM.name,
                rPARAM.age,rPARAM.classN);

}
写的不够完全,只供参考,
struct student {
                struct student *next;
                char  *name;
                __u32 age;
                long  id;
                __u16 class;
                char  classN[32];               
};
struct studentUsr {
                char  *name;
                __u32 age;
                long  id;
                __u16 class;
                char  classN[32];               
};
struct class{
                __u16 class;
                char  classN[32];
                __u32 count;
                struct student *list; 
};

struct class g_arClass[5][5]  // 存储有的班级信息的全局变量数组

/*形参__user *arg  表示 user 层传递给Kernel 的学生信息,  
 1.首先需要通过access_ok 检测其有效性 ,如果无效,要访问error 信息
2.其次需要 通过 copy_from_user 将user层数据 传递到 kernel 层的(rParam)
3.最后就是解析  rParam 数据,并保存到储有的班级信息的全局变量数组  */
int add_student(void __user *arg)
{
                int ret = 0;
                struct studentUsr rParam;
                struct student  st1;
                int grade , class;

                memset(&rParam, 0, sizeof(rParam));
                if (0 == access_ok(VERIFY_READ | VERIFY_WRITE,(void *arg),sizeof(rPARAM))) {   // access_ok 检测其有效性
                                return (–EACCESS);
                }              

                ret =  copy_from_user((void *)&rParam,(void *)arg, sizeof(rParam));  //  copy_from_user 将user层数据 传递到 kernel 层的(rParam
                if (0 != ret) {
                                                /* encounter error */
                                                return (–EACCESS);
                }

                /*根据题事例:例如class为0501的是代表5年级1班,采取以下方法或者 年级 与 班级 信息*/
                grade= rPARAM.class/100 ;   // get 年级 info
                class= rPARAM.class%100 ;  // get 班级 info

                if(grade>4||class>4)   // 全局数组最大是 [5][5]  , 这里做一个error check 操作
                                return (–EACCESS);


                /*填充  g_arClass[][] .list 的成员*/              
                memcpy(st1.name,rPARAM.name,sizeof (rPARAM.name));
                memcpy(st1.classN,rPARAM.classN,sizeof (rPARAM.classN));
                st1.age=rPARAM.age;
                st1.id=rPARAM.age;
                st1.class=rPARAM.class/*填充  g_arClass[][]  的成员,就是题意的要求*/             
                g_arClass[grade-1][class-1].class=st1.class;
                memcpy(g_arClass[grade-1][class-1].classN,rPARAM.classN,sizeof (rPARAM.classN));
                g_arClass[grade-1][class-1].list=&st1;

/*打印添加的学生信息*/
                printk("name is %s, age is %d , classN is %s \n",rPARAM.name,
                rPARAM.age,rPARAM.classN);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值