1.问题内核中有些变量为什么不初始化就敢直接使用?2.分析上图。5747行的变量nid确实没有定义,所以直接使用。这有什么问题吗?其实大家仔细看看,5765行是一个宏,去内核源码中找到宏的定义:linux-3.14\include\linux\Nodemask.h#definefor_each_online_node(node)for_each_node_state(node,N_ONLINE)其中for_each_node_state是另一个宏,继续跟踪宏,有两个定义408#ifMAX_NUMNODES>1...429#definefor_each_node_state(__node,__state)\430for_each_node_mask((__node),node_states[__state])...450#else...470#definefor_each_node_state(node,__state)\471for((node)=0;(node)==0;(node)=1)...481#endif哪个定义由条件#ifMAX_NUMNODES决定>1、#ifdefCONFIG_NODES_SHIFT#defineNODES_SHIFTCONFIG_NODES_SHIFT#else#defineNODES_SHIFT0#endif#defineMAX_NUMNODES(1<117#definefor_each_node_state(__node,__state)\18for_each_node_mask((__node),node_states[__state])19#else20#definefor_each_node_state(node,__state)\21for((node)=0;(node)==0;(node)=1)22#endif2324252627#definefor_each_online_node(node)for_each_node_state(node,N_ONLINE)282930staticint__build_all_zonelists(void*data)31{32intnid;33intcpu;34pg_data_t*self=data;35363738for_each_online_node(nid){39pg_data_t*pgdat=NODE_DATA(nid);4041build_zonelists(pgdat);42build_zonelist_cache(pgdat);43}44}第二步定义宏并使用下面命令展开,gcc-E-E的意思是对文件进行编译和预处理,但不生成汇编代码,只替换文件中的宏定义和包含的头文件,不检查语法是否正确正确与否。结果如下:peng@ubuntu:~/test$gcc123.c-E#1"123.c"#1""#1""#1"/usr/include/stdc-predef.h"134#1"<命令行>"2#1"123.c"#28"123.c"staticint__build_all_zonelists(void*data){intnid;intcpu;pg_data_t*self=data;for((nid)=0;(nid)==0;(nid)=1){pg_data_t*pgdat=NODE_DATA(nid);build_zonelists(pgdat);build_zonelist_cache(pgdat);}}由结果可知nid赋值为0。5.练习让我们做一个练习,展开内核的wait_event()宏副本,并使用c文件中的所有宏定义。wait.c12#define___wait_event(wq,condition,state,exclusive,ret,cmd)\3({\4__label____out;\5wait_queue_t__wait;\6long__ret=ret;\7\8INIT_LIST_HEAD(&__wait.task_list);\9if(exclusive)\10__wait.flags=WQ_FLAG_EXCLUSIVE;\11else\12{\13/*code*/\14__wait.flags=0;\15\16for(;;){\17long__int=prepare_to_wait_event(&wq,&__wait,state);\18\19if(条件)\20break;\21\22if(___wait_is_interruptible(state)&&__int){\23__ret=__int;\24if(exclusive){\25abort_exclusive_wait(&wq,&__wait,\26state,NULL);\27goto__out;\28}\29break;\30}\31\32cmd;\33}\34finish_wait(&wq,&__wait);\35__out:__ret;\36})\37}\3839404142#defineTASK_UNINTERRUPTIBLE2434445#define__wait_event(wq,condition)\46(void)___wait_event(wq,条件,TASK_UNINTERRUPTIBLE,0,0,\47schedule())\48\49\50wait_event(wq,condition)\51do{\52if(condition)\53break;\54__wait_event(wq,condition);\55}while(0)\56575859test()60{62wait_event(wq,flag==0);64}编译与处理结果如下:root@ubuntu:/home/peng/test#gccwait.c-E#1"wait.c"#1"<内置>"#1"<命令行>"#1"/usr/include/stdc-predef.h"134#1"<命令行>"2#1"wait.c"#71"wait.c"test(){do{if(flag==0)break;(void)({__label____out;wait_queue_t__wait;long__ret=0;INIT_LIST_HEAD(&__wait.task_list);if(0)__wait.flags=WQ_FLAG_EXCLUSIVE;else{__wait.flags=0;for(;;){long__int=prepare_to_wait_event(&wq,&__wait,2);if(flag==0)break;if(___wait_is_interruptible(2)&&__int){__ret=__int;if(0){abort_exclusive_wait(&wq,&__wait,2,NULL);goto__out;}break;}schedule();}finish_wait(&wq,&__wait);__out:__ret;})};}while(0);}函数test()整理如下:test(){do{if(flag==0)break;(void)({__label____out;wait_queue_t__wait;long__ret=0;INIT_LIST_HEAD(&__wait.task_list);如果(0)__wait.flags=WQ_FLAG_EXCLUSIVE;else{__wait.flags=0;for(;;){long__int=prepare_to_wait_event(&wq,&__wait,2);if(flag==0)break;if(___wait_is_interruptible(2)&&__int){__ret=__int;if(0){abort_exclusive_wait(&wq,&__wait,2,NULL);goto__out;}break;}schedule();}finish_wait(&wq,&__wait);__out:__ret;})};}while(0);}这是wait_event()最终被替换后的代码,你学会了吗?六、16个经典宏定义小例子数值相关的宏定义1闰年的判断,年份能被4整除且不能被100整除,或者能被400整除,则为闰年;#defineIS_LEAP_YEAR(y)(((((y)%4)==0)&&(((y)%100)!=0))\||(((y)%400)==0))/*判断是否为闰年*/2**MAX和MIN**;#defineMAX(x,y)(((x)<(y))?(y):(x))/*取两个数中的最大值*/#defineMIN(x,y)(((x)<(y))?(x):(y))/*取两个数中的最小值*/3个BCD码;#defineBCD2HEX(x)(((x)>>4)*10+((x)&0x0F))/*BCD码转换值,20H->20*/#defineHEX2BCD(x)(((x)%10)+((((x)/10)%10)<<4))/*数字转BCD码,20->20H*/4字符相关宏定义字符范围判断/*字符是否在某个*/#definein_range(c,lo,up)((uint8)c>=lo&&(uint8)c<=up)#defineisprint(c)in_range(c,0x20,0x7f)/*十进制字符*/#defineisdigit(c)in_range(c,'0','9')/*十六进制字符*/#defineisxdigit(c)(isdigit(c)||in_range(c,'a','f')||in_range(c,'A','F'))/*是否为小写*/#defineislower(c)in_range(c,'a','z')/*是否为空格*/#defineisspace(c)(c==''||c=='\f'||c=='\n'||c=='\r'||c=='\t'||c=='\v')/*ASCII码*/#defineisascii(c)((unsigned)(c)<=0177)5字节相关宏定义#defineMSB(x)(((x)>>8)&0xff)/*x占2byte(如short)2byte高地址的1byte*/#defineLSB(x)((x)&0xff)/*x占2byte(如short)2byte低地址的1byte*/#defineMSW(x)(((x)>>16)&0xffff)/*x占4byte高地址的2byte(比如int)4byte*/#defineLSW(x)((x)&0xffff)#defineWORDSWAP(x)(MSW(x)|(LSW(x)<<16))/*x占4个字节(比如int),低2字节和高2字节交换*/#defineLLSB(x)((x)&0xff)/*x占4个字节(比如int)取低地址1byte*/#defineLNLSB(x)(((x)>>8)&0xff)#defineLNMSB(x)(((x)>>16)&0xff)#defineLMSB(x)(((x)>>24)&0xff)/*x占4个字节(比如int)倒序4个字节*/#defineLONGSWAP(x)((LLSB(x)<<24)\|(LNLSB(x)<<16)\|(LNMSB(x)<<8)\|(LMSB(x)))6位相关宏定义/*判断某位是否为1*/#defineBIT_IS_1(x,y)(((x)>>(y))&0x01u)#defineSETBITS(x,y,n)(x)=(n)?((x)|(1<<(y))):((x)&(~(1<<(y))));/*反转一个位置*/#defineBIT_INVERSE(x,y)((x)=(x)^(1<<(y)))/*字节串中的一个BIT值*/#defineBIT_OF_BYTES(x,y)(BITS(x[(y)/8],(y)%8))/*设置字节串中的某个BIT为0*/#defineSETBITSTO0_OF_BYTES(x,y)(x[(y)/8])&=(~(1<<((y)%8)))/*设置字节串中的某个BIT为1*/#defineSETBITSTO1_OF_BYTES(x,y)(x[(y)/8])|=(1<<((y)%8))7数组和结构相关的宏定义/*numberofelementsinarray*/#defineARRAY_SIZE(a)(sizeof(a)/sizeof((a)[0]))/*byteoffsetofmemberinstructure*/#defineMOFFSET(structure,member)((int)&(((structure*)0)->member))/*sizeofamemberofastructure*/#defineMEMBER_SIZE(structure,member)(sizeof(((structure*)0)->member))8宏定义用于对齐/*向上对齐,~(align-1)为对齐掩码,例如align=8,~(align-1)=~7,(~7)二进制000的最后三位,&(~(align-1))=&(~7),就是去掉余数,使其能被8整除*/#defineALIGN_UP(x,align)(((int)(x)+(align-1))&~(align-1))/*向下对齐*/#defineALIGN_DOWN(x,align)((int)(x)&~(align-1))/*对齐*/#defineALIGNED(x,align)(((int)(x)&(align-1))==0)/*页面对齐相关宏,一页为4096字节*/#definePAGE_SIZE4096#definePAGE_MASK(~(PAGE_SIZE-1))#definePAGE_ALIGN(addr)-(((addr)+PAGE_SIZE-1)&PAGE_MASK)9防止头文件被重复包含#ifndefBODY_H//保证只有不包含头文件才会展开内容#defineBODY_H//头文件内容#endif10获取指定地址处的一个字节或一个字#defineMEM_B(x)(*(byte*)(x))//获取x所代表的地址处的一个字节#defineMEM_W(x)(*(word*)(x))//获取x所代表的地址上的一个word11获取一个字段在结构体中的偏移量#defineOFFSET(type,field)(size_t)&((type*)0->field)12获取一个结构体中字段占用的字节数#defineFSIZ(type,field)sizeof(((type*)0)->field)13获取一个变量的地址#defienB_PTR(var)((byte*)(void*)&(var))//获取字宽的地址#defineW_PTR(var)((word*)(void*)&(var))//获取字宽14的地址a将字母转换为大写#defineUPCASE(c)(((c)>="a"&&(c)<="z")?((c)-0x20):(c))15防止溢出#defineINC_SAT(val)(val=((val)+1>(val))?(val)+1:(val))16返回数组元素个数#defineARR_SIZE(a)(sizeof((a))/sizeof(a[0])))