zoukankan      html  css  js  c++  java
  • 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:

  • 相关阅读:
    OLTP与OLAP
    Entity Framework(07):TPH、TPT、TPC与继承类
    Entity Framework(05):主从表的增删改
    Entity Framework(06):配置关系
    Entity Framework(04):主从表数据加载方式
    Entity Framework(03):Code First基础
    Entity Framework(02):模型优先 ,ObjectContext类
    Entity Framework(01):模型优先,Linq to Entities
    简介LINUX远程联机软件:PUTTY、SecureCRT、X-Manager
    php函数分割
  • 原文地址:https://www.cnblogs.com/gakusei/p/14431129.html
Copyright © 2011-2022 走看看