systemd IN_SET宏展开分析

{{MARKDOWN}}

# systemd IN_SET宏展开分析
## IN_SET宏的定义
```
#define IN_SET(x, ...) \
({ \
bool _found = false; \
/* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \
* type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \
* the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \
* doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \
assert_cc((sizeof((long double[]){__VA_ARGS__})/sizeof(long double)) <= 20); \
switch(x) { \
FOR_EACH_MAKE_CASE(__VA_ARGS__) \
_found = true; \
break; \
default: \
break; \
} \
_found; \
})
```
其中,({})的使用很巧妙,使宏可以用在if条件中,也可以作为独立代码行。

## IN_SET宏的作用
IN_SET(x, ...)表达的宏参数x是否被剩余宏参数集合包含,如果包括就IN_SET返回true, 否则返回false,使用起来特别方便。
下面看一个使用示例:
```
static int acquire_bus(sd_bus **bus, bool *use_full_bus) {
bool user = arg_scope != UNIT_FILE_SYSTEM;
int r;

if (use_full_bus && *use_full_bus) {
r = bus_connect_transport(arg_transport, arg_host, user, bus);
//如果r等于0或者-EHOSTDOWN,就执行return r;
if (IN_SET(r, 0, -EHOSTDOWN))
return r;

*use_full_bus = false;
}

return bus_connect_transport_systemd(arg_transport, arg_host, user, bus);
}
```

## 分析IN_SET宏作用机制
IN_SET宏的实现,主要是依赖C99可变参数宏 __VA_ARGS___:
```
/home/ttt/Desktop/sharedata/systemd/systemd-241.7+c2/src/basic/macro.h
#define CASE_F(X) case X: //展开为一个 case xxx:
#define CASE_F_1(CASE, X) CASE_F(X) //丢弃CASE,并展开为一个 case xxx:
#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) //CASE这里传来的一般是CASE_F,见FOR_EACH_MAKE_CASE。结果是展开为一个case xxx,再透传CASE与__VA_ARGS__,注意这里的__VA_ARGS__不包括X
#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) //类似CASE_F_2,但是比CASE_F_2的__VA_ARGS__多一个X,即每递归展开一层,就多展开个case xxx且吃掉一个不定参数
#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)

#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME

#define FOR_EACH_MAKE_CASE(...) \
GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
(CASE_F,__VA_ARGS__)
```


### GET_CASE_F
GET_CASE_F作用是返回第21个宏参数。
GET_CASE_F本身支持21+个参数,但在FOR_EACH_MAKE_CASE中使用时,如果参数个数大于40个(即FOR_EACH_MAKE_CASE的__VA_ARGS__个数大于20)返回的NAME就无意义。


### FOR_EACH_MAKE_CASE
FOR_EACH_MAKE_CASE,这里的__VA_ARGS__个数必须在[1,20]之间
__VA_ARGS__的个数为N, 那么这里GET_CASE_F的结果就为CASE_F_N,且N必须在[1,20]之间
比如FOR_EACH_MAKE_CASE(11,22)逐步展开过程为:
1、CASE_F_2(CASE_F, 11, 22)
2、case 22: case 11:

posted @ 2021-02-22 16:34  荷包蛋  阅读(127)  评论(0编辑  收藏  举报