• OC 实现一个TODO宏


    实现一个TODO宏

    转载http://blog.sunnyxx.com/2015/03/01/todo-macro/

    实现一个能产生warning的TODO宏,用于在代码里做备忘,效果:

    代码效果
    编译效果

    下面一步步来实现这个宏。

    Let’s do it

    手动让编译器报警(报错)可以用以下几个方法:

    #warning sunnyxx
    #error sunnyxx
    #pragma message "sunnyxx"
    #pragma GCC warning "sunnyxx"
    #pragma GCC error "sunnyxx"
    

    但我们知道,带 # 的预处理指令是无法被 #define 的。好在C99提供了一个 _Pragma 运算符可以把部分 #pragma 指令字符串化:

    #pragma message "sunnyxx"
    // 等价于
    _Pragma("message "sunnyxx"") // 需要注意双引号的转义
    // 或
    _Pragma("message("sunnyxx")") // 需要注意双引号的转义
    

    1.利用这个特性,我们就可以将warning定义成宏

    #define SOME_WARNING _Pragma("message("报告大王!")")
    
    int main() {
        SOME_WARNING // [!]报告大王!
        return 1;
    }
    

    2.接下来,我们让这个宏能够接受入参,并显示到warning中去,这里会面临宏的基本用法的考验。

    #define STRINGIFY(S) #S
    #define PRAGMA_MESSAGE(MSG) _Pragma(STRINGIFY(message(MSG)))
    

    3.个人认为不太可能在一个宏定义中完成这件事,需要用到辅助宏:STRINGIFY(S) 将入参转化成字符串,省去了_Pragma中全串加转义字符的困扰。

    这时,一个基本功能的TODO宏就完成了,下面向其中加入额外的信息:

    // 两个已有的宏
    #define STRINGIFY(S) #S
    #define PRAGMA_MESSAGE(MSG) _Pragma(STRINGIFY(message(MSG)))
    // 延迟1次展开的宏
    #define DEFER_STRINGIFY(S) STRINGIFY(S)
    // 下面的宏在第一行用`\`折行
    #define FORMATTED_MESSAGE(MSG) "[TODO-" DEFER_STRINGIFY(__COUNTER__) "] " MSG " 
    "  
        DEFER_STRINGIFY(__FILE__) " line " DEFER_STRINGIFY(__LINE__)
    

    其中涉及到的知识:

    1. 两个常量字符串可以拼接成一个整串 “123””456” => “123456”
    2. 使用到3个预定义宏,__COUNTER__宏展开次数的计数器,全局唯一;__FILE__当前文件完整目录字符串;__LINE__在当前文件第几行
    3. 在字符串中预定义宏应延时展开,如果将上面的DEFER_STRINGIFY换成STRINGIFY的话,如__LINE__就不能被正确展开成行数,而是成了一个常量字符串"LINE"
    4. 为了美化,warning message中可以使用 换行

    于是,使用FORMATTED_MESSAGE(MSG)宏就可以将带文件路径、序号、行数等信息加入到最终的warning中。

    4.其实到这步已经OK了,为了让这个宏更加抢眼,还可以借鉴RAC,把宏定义成前面加@的形式:

    #define KEYWORDIFY try {} @catch (...) {}
    

    5.将最终的宏定义前面加上上面的宏后,使用时就可以加@前缀了(空的try-catch会被编译器优化,所以没啥性能损耗)

    最终版本

    #define STRINGIFY(S) #S
    #define DEFER_STRINGIFY(S) STRINGIFY(S)
    #define PRAGMA_MESSAGE(MSG) _Pragma(STRINGIFY(message(MSG)))
    #define FORMATTED_MESSAGE(MSG) "[TODO-" DEFER_STRINGIFY(__COUNTER__) "] " MSG " 
    " 
    DEFER_STRINGIFY(__FILE__) " line " DEFER_STRINGIFY(__LINE__)
    #define KEYWORDIFY try {} @catch (...) {}
    // 最终使用下面的宏
    #define TODO(MSG) KEYWORDIFY PRAGMA_MESSAGE(FORMATTED_MESSAGE(MSG))
    

    What’s more

    Xcode插件《XTodo》也是利用这个特性,可以尝试下。

    如果需要一个产生error的宏,将这里替换成这样就好了:_Pragma(STRINGIFY(GCC error(MSG)))

    References

    http://clang.llvm.org/docs/UsersManual.html
    https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

  • 相关阅读:
    Android学习——SAX解析方式
    Android学习——pull解析方式
    Android学习——使用okhttp
    开课第十五周周总结
    顶会热词3
    顶会热词2
    顶会热词1
    配置JAVA环境
    配置mybaits的一些坑
    Maven配置和idea种tomcat配置的一些坑点
  • 原文地址:https://www.cnblogs.com/ShaoYinling/p/7803914.html
Copyright © 2020-2023  润新知