一、问题
为啥内核有的变量没有初始化就敢直接使用?
二、分析
看上图,其中的5747行的变量nid的确没有定义,就直接使用了,这么做没有问题吗?
其实大家仔细看一下,5765行是一个宏,
到内核源码去找该宏的定义:linux-3.14includelinuxNodemask.h
#define for_each_online_node(node) for_each_node_state(node, N_ONLINE)
其中的for_each_node_state又是一个宏,继续跟踪该宏,有两处定义
408 #if MAX_NUMNODES > 1
……
429 #define for_each_node_state(__node, __state)
430 for_each_node_mask((__node), node_states[__state])
……
450 #else
……
470 #define for_each_node_state(node, __state)
471 for ( (node) = 0; (node) == 0; (node) = 1)
……
481 #endif
究竟是哪一个定义,由条件#if MAX_NUMNODES > 1 来决定,
#ifdef CONFIG_NODES_SHIFT
#define NODES_SHIFT CONFIG_NODES_SHIFT
#else
#define NODES_SHIFT 0
#endif
#define MAX_NUMNODES (1 << NODES_SHIFT)
因为CONFIG_NODES_SHIFT没有定义【可以检索一下内核,找不到该宏的定义】,所以NODES_SHIFT 为0
所以 MAX_NUMNODES 为1;
所以 for_each_node_state 定义如下:
470 #define for_each_node_state(node, __state)
471 for ( (node) = 0; (node) == 0; (node) = 1)
而此处的node 对应 粉丝截图的nid,__state 对应 N_ONLINE
所以5765行代码,可以展开为
for ( (nid) = 0; (nid) == 0; (nid) = 1)
可见,nid被定义了。
三、宏定义的注意点
宏定义是一个给定名称的代码片段,当我们使用这个名称的时候,预处理器会自动将其替换为宏定义的内容。宏定义有两种,一种是object-like宏定义,在使用的时候相当于一个数据对象;另一种是function-like,在使用的时候就像调用函数那样。
1. 只占用编译时间
宏展开会使源程序变长,但是宏展开发生在编译过程中,不占运行时间,只占编译时间。
宏展开因为在预处理阶段发生,不会分配内存。
2. 宏替换发生时机
编译c源程序的过程:
预处理编译汇编连接
宏替换发生在编译预处理阶段。
3. 预处理包括哪些工作
预处理产生编译器的输出,实现功能如下
1)文件包含
把#include中包含的内容拓展为文件的正文,即找到.h文件,同时展开到#include所在处
2)条件编译
根据#if和#ifdef等编译命令,将源程序文件中的部分包含进来,部分排除,排除在外的一般转换为空行