• android-CHECK_xxx分析


    android-CHECK_xxx

    在这里插入图片描述
    在android源码中有不少类似这样的用法,上图中就是检查获得的hal版本是否大于等于版本1_3,满足继续往下走,不满足则assert,并报错。
    接下来就展开看看CHECK_xx家族:

    用法

    类型用法含义
    CHECK_EQ(val1, val2)==检查左右val1与val2是否相等,相等则通过,否则assert并输出error log
    CHECK_NE(val1, val2)!=检查左右val1与val2是否不相等,不相等则通过,否则assert并输出error log
    CHECK_LE(val1, val2)检查左右val1是否小于等于val2,小于等于则通过,否则assert并输出error log
    CHECK_LT(val1, val2)检查左右val1是否小于val2,小于则通过,否则assert并输出error log
    CHECK_GE(val1, val2)检查左右val1是否大于等于val2,大于等于则通过,否则assert并输出error log
    CHECK_GT(val1, val2)检查左右val1是否大于val2,大于则通过,否则assert并输出error log
    #define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
    #define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
    #define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
    #define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
    #define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
    #define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
    
    #define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
    // Helper macro for binary operators.
    // Don't use this macro directly in your code, use CHECK_EQ et al below.
    // The 'switch' is used to prevent the 'else' from being ambiguous when the
    // macro is used in an 'if' clause such as:
    // if (a == 1)
    //   CHECK_EQ(2, a);
    #define CHECK_OP(name, op, val1, val2)                                         \
      switch (0) case 0: default:                                                  \
      if (::logging::CheckOpResult true_if_passed =                                \
          ::logging::Check##name##Impl((val1), (val2),                             \
                                       #val1 " " #op " " #val2))                   \
       ;                                                                           \
      else                                                                         \
        ::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
    
    #endif  // !(OFFICIAL_BUILD && NDEBUG)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    switch (0) case 0: default:当宏被用在一个if子句中时,'switch’用于防止’else’不明确

    以CHECK_GE为例分析源码

    #define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
    
    • 1

    CHECK_OP(GE, >=, val1, val2)展开后

    if (::logging::CheckOpResult true_if_passed = ::logging::CheckGEImpl((val1), (val2), "val1 >= val2")
      ;
    else
      ::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
    
    • 1
    • 2
    • 3
    • 4

    实际上跳到另一个宏Check##name##Impl去执行了,看返回结果true_if_passed是不是为真,若为假则打印出信息,这里的LogMessage是一个类,根据文件名、行号、日志级别构建对象,之后执行LogMessage::stream()输出信息
    看看宏Check##name##Impl

      inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
        if (ANALYZER_ASSUME_TRUE(v1 op v2))                                      \
          return NULL;                                                           \
        else                                                                     \
          return ::logging::MakeCheckOpString(v1, v2, names);                    \
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    CheckGEImpl展开后,在这里#op是>=

        if (ANALYZER_ASSUME_TRUE(val1 >= val2))
          return NULL;
        else
          return ::logging::MakeCheckOpString(v1, v2, names);
    
    • 1
    • 2
    • 3
    • 4

    看看宏ANALYZER_ASSUME_TRUE,在clang_analyzer中加静态分析,返回参数val1 >= val2是否为真,若为真返回NULL,Check_xxx通过。ANALYZER_ASSUME_TRUE常与断言和类断言函数一起使用。

    inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
      return false;
    }
    
    inline constexpr bool AnalyzerAssumeTrue(bool arg) {
      // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is
      // false.
      return arg || AnalyzerNoReturn();
    }
    
    #define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    若ANALYZER_ASSUME_TRUE返回假,则进到else中的MakeCheckOpString,负责构建错误消息字符串,就不再展开了

    // Build the error message string.  This is separate from the "Impl"
    // function template because it is not performance critical and so can
    // be out of line, while the "Impl" code should be inline.  Caller
    // takes ownership of the returned string.
    template<class t1, class t2>
    std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
      std::ostringstream ss;
      ss << names << " (";
      MakeCheckOpValueString(&ss, v1);
      ss << " vs. ";
      MakeCheckOpValueString(&ss, v2);
      ss << ")";
      std::string* msg = new std::string(ss.str());
      return msg;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    【uniapp】设置swiper组件禁止手动滑动失效的问题
    PCI Pharma Services宣布斥资数百万美元扩建英国制造设施,以满足市场对支持肿瘤治疗的全球高效药制造服务日益增长的需求
    Java最新面试宝典 Spring面试题
    Java程序员面试大厂95%会被问到的25个问题(附答案)
    Hive 到底有什么用?
    Pytorch编程基础
    图解redis(二)——持久化篇
    k8s pod 处于Terminating的原因分析和解决处理——筑梦之路
    图像下载的新趋势:Kotlin技术探索与实践
    解锁区块链游戏数据解决方案
  • 原文地址:https://blog.csdn.net/qq_43792862/article/details/127995639