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);
}