在代码的阅读过程中,总时不时地遇到LIST_FOR_EACH_SAFE这一个宏定义,从字面上来看,它的功能无非就是对一个列表进行循环,类似于Java中的foreach:for (item : List),Python之中的for item in List等。在诸多高级语言之中,都能够发现对foreach的支持,但在C语言里面,暂时还没有发现其对foreach的原生的支持。
所以在这里我们可以看到开发者为了解决这一问题,同时使得代码表达更为简洁,使用到了C语言的宏定义来解决这一个问题。
首先,在C语言里面:
1 | for (语句1; 语句2; 语句3) |
for语句的执行步骤如下:
- 执行语句1;
- 执行语句2,若其值为真,则执行 for 语句中的循环体;若语句2值为假,则结束循环,转到第5步。
- 执行语句3;
- 跳转第2步继续执行;
- 循环结束,执行 for 语句下面的语句。
LIST_FOR_EACH_SAFE的宏定义如下:
1 |
|
例如在authmanager\source\auth_interface.c中的就是:
1 | LIST_FOR_EACH_SAFE(pos, tmp, g_sessionKeyList) { |
所以,从语句1之中可以看到,g_sessionKeyList代表的是列表的头节点,将其next的值(即第零个节点的指针)赋给了pos,再结合语句3可以看到tmp存储着的是下一个节点的指针,即在循环体执行完成之后,会把下一个节点的值赋给到pos,tmp再存储下下个节点的指针。
在语句2之中可以看到,进入循环之前会对pos的值进行判断,如果为空(空指针)则代表着列表为空或是已经遍历完成,可以退出for循环了。
紧接着我在循环体内看到了这么一句有趣的代码:
1 | node = (SessionKeyNode *)pos; |
其中:
1 | List *pos = NULL; |
可以看到,List结构体的指针被强制转换为了SessionKeyNode结构体的指针。
而这两个结构体在内存里面存储的结构如下:

List结构体“寄生”在了SessionKeyNode结构体之中,这是因为在SessionKeyNode的定义之中,并不是定义List结构体的指针,而是定义的整个List结构体,所以在SessionKeyNode结构体之中会为其开辟一块大小等同的空间用于存储prev和next这两个指针。
这就有点类似于面向对象中的类的继承,但C语言是一门面向过程的语言,并不原生支持面向对象的操作。所以开发人员在这里采用了强转类型的方法巧妙的将其实现了。
且这一个结构体的类型强转仅是限制于结构体指针,并不能够直接对结构体进行强转。这一种强制转换就类似告诉编译器需要根据哪一个结构体对这一个指针进行操作。
总而言之,指针只是提供了一个入口,需要去到哪里是有编译器根据结构体来定。
历史文章
代码标注仓库:
https://forgeplus.trustie.net/projects/p27896134/OpenHarmonySoftbusCodeComment