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 " \n" \
DEFER_STRINGIFY(__FILE__) " line " DEFER_STRINGIFY(__LINE__)
其中涉及到的知识:
- 两个常量字符串可以拼接成一个整串 “123””456” => “123456”
- 使用到3个预定义宏,__COUNTER__宏展开次数的计数器,全局唯一;__FILE__当前文件完整目录字符串;__LINE__在当前文件第几行
- 在字符串中预定义宏应延时展开,如果将上面的DEFER_STRINGIFY换成STRINGIFY的话,如__LINE__就不能被正确展开成行数,而是成了一个常量字符串"LINE"
- 为了美化,warning message中可以使用\n换行
于是,使用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 " \n" \
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
OC 实现一个TODO宏的更多相关文章
- 代码备忘, TODO宏实现
代码备忘, TODO宏实现 我们平时在开发过程中, 往往并非憋足气一股脑敲完所有代码.每一个模块, 每一个函数的实现总有个先后顺序. 又或者哪个部分须要做调整, 改动- 所以, 我们须要有一个东西, ...
- 用 Swift 开发一个 TODO 应用
背景 相信不少 iOS 程序员对于 Swift 依旧持以观望的态度,一来是这小家伙刚出来没几天,本身还处于完善的阶段:二来是学习的成本较高,看完官方文档怎么也要个几天的时间:三来是反正最近几年很难在工 ...
- oc是一个全动态语言,oc的一切都是基于runtime实现的!
oc是一个全动态语言,oc的一切都是基于runtime实现的! 从以下三方面来理解runtime吧! 1. 传统的面向过程的语言开发,例如c语言.实现c语言编译器很简单,只要按照语法规则实现一个LAL ...
- 用react + redux + router写一个todo
概述 最近学习redux,打算用redux + router写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 注意: 我只实现了Footer组件的router,其它组件的实现方法是类 ...
- 用react+redux写一个todo
概述 最近学习redux,打算用redux写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 代码 代码请见我的github 组织架构如下图:
- react写一个todo
概述 最近学习redux,打算先复习一下react,所以用react写了一个todo.记录下来,供以后开发时参考,相信对其他人也有用. 代码 代码请见我的github 组织架构如下图:
- Confluence 6 创建一个用户宏
如果你想创建自定义的宏的话,用户宏能够帮你完成这个任务.这个可以在你系统中应用特定的操作,比如说应用自定义格式等. 用户用是在 Confluence 创建和和管理的,你需要有一定的编码基础才可以. 你 ...
- Directx11教程(11) 增加一个debug宏
原文:Directx11教程(11) 增加一个debug宏 现在我们在common.h中增加一个debug的宏,在每个d3d11函数后调用,如果d3d函数出错,它能够给出程序中错误的代码行 ...
- 写一个TODO App学习Flutter本地存储工具Moor
写一个TODO App学习Flutter本地存储工具Moor Flutter的数据库存储, 官方文档: https://flutter.dev/docs/cookbook/persistence/sq ...
随机推荐
- A Simple Example About Privileged Methods in JavaScript
Douglas Crockford classified the "class methods" in JavaScript into three types: private, ...
- BZOJ1087=Codevs2451=洛谷P1896&P2326互不侵犯
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2885 Solved: 1693[Submit][ ...
- (14)javaWeb中的HttpServletResponse类详解
如果希望了解请求和响应的详细内容,可以看我的“HTTP协议”系列文章 响应体的简单概述: a,响应报文结构: b,常见的状态码,返回服务器处理的结果: c,常见的响应头: HttpServletRes ...
- jdk 版本不一致导致的错误
平时做项目时难免会从git,svn下载代码或者把别人的项目文件导入到自己的MyEclipse中进行操作,因此会遇到很多问题,常见的有一种是使用的jdk版本不一致造成的报错, 错误案例: 错误提 ...
- YTU 2897: E--外星人供给站
2897: E--外星人供给站 时间限制: 2 Sec 内存限制: 128 MB 提交: 20 解决: 13 题目描述 外星人指的是地球以外的智慧生命.外星人长的是不是与地球上的人一样并不重要,但 ...
- 织梦dedecms将指定图片自动生成指定尺寸的小图、缩略图、图片的方法
对于普通企业网站来讲,织梦原来的程序只是提供了一个缩略图,但是这样对于一些相对来说图片会比较多的网站来说,图片太大当缩略图会导致网站整体的访问速度,所以我今天就来教你织梦把一张大图转换成生成一张小图或 ...
- Rebel 6 破解版及使用方法
下载地址:http://www.zeroturnaround.com/jrebel/download/ 下载下来的是一个Zip压缩包,打开之后会发现一个jrebel.jar,这就是其最重要的运 ...
- 转载别人的ognl
一.循环遍历集合 1.在jsp中引入标准函数声明<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix=" ...
- div拖拽互换位置(vue)
template模板 <transition-group tag="div" class="container"> <div class=&q ...
- bzoj 3105: [cqoi2013]新Nim游戏【线性基+贪心】
nim游戏的先手必胜条件是所有堆的火柴个数异或和为0,也就是找一个剩下火柴堆数没有异或和为0的子集的方案,且这个方案保证剩下的火柴个数总和最大 然后我就不会了,其实我到现在也不知道拟阵是个什么玩意-- ...