代码备忘, TODO宏实现

代码备忘, TODO宏实现

我们平时在开发过程中, 往往并不是憋足气一股脑敲完全部代码。每个模块, 每个函数的实现总有个先后顺序。又或者哪个部分需要做调整, 修改… 所以, 我们需要有一个东西, 来提醒我们, 起到代码备忘功能, 避免某个功能忘记实现, 也能让我们快速定位。 所以这篇文章, 就是要实现一个TODO宏, 来达到代码备忘功能。

效果如下:

下面来分析下如何实现这个宏



在实现TODO之前, 已经自带了几个预处理指令来实现报警/报错:

#warning Colin
#error Colin
#pragma message "Colin"
#pragma GCC warning "Colin"
#pragma GCC error "Colin"

效果如下:

既然有了, 那为什么还需要自己实现这个TODO宏呢?

  1. error 和 warning所代表的意义已经深入猿心, 我们没有理由使用它来做备忘。
  2. 如果也使用warning, 在警告导航栏中, 我们很难区分哪个才是我们手动打的标记, 哪个是程序本身的warning
  3. 带#的预处理指令是无法被#define的, 也就是没办法直接利用这个来定义我们的TODO

好在C99提供了一个 _Pragma 运算符可以把部分#pragma指令字符串化, 如下:

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

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

#define MY_WARNING _Pragma("message (\"警察临检, 男左女右!\")")

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    MY_WARNING
}

效果如下:

到这里, 大体有那么一个感觉。 不过我们提示的内容, 是define的, 也就是写死固定的, 不太合适。

所以我们希望这个宏能接受入参, 让它正常显示到warning中。

这就涉及了一些宏的基本用法。

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

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中。



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

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

最终版本


// 转成字符串
#define STRINGIFY(S) #S
// 需要解两次才解开的宏
#define DEFER_STRINGIFY(S) STRINGIFY(S)

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

// 为warning增加更多信息
#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))

References

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

http://clang.llvm.org/docs/UsersManual.html

https://gcc.gnu.org/onlinedocs/cpp/Pragmas.html

时间: 2024-10-07 05:30:13

代码备忘, TODO宏实现的相关文章

【代码备忘】火狐浏览器插件xpi自动从网站下载安装的代码

欢迎加入我们的QQ群,无论你是否工作,学生,只要有c / vc / c++ 编程经验,就来吧!158427611 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml&

ffplay for mfc 代码备忘

之前上传了一个开源播放器工程ffplay for mfc.它将ffmpeg项目中的ffplay播放器(ffplay.c)移植到了VC的环境下,并且使用MFC做了一套界面.它可以完成一个播放器播放视频的基本流程:解协议,解封装,视频/音频解码,视音频同步,视音频输出.此外还包含一些控制功能:播放,暂停/继续,前进,后退,停止,逐帧播放,全屏等:以及一些码流分析功能:视频解码分析和音频解码分析. 详细的软件使用就不仔细介绍了,本文简单介绍其中比较重要的模块的流程.以防长时间不看的话忘了~ 软件信息:

【代码备忘】VC判断自己窗口的另一种方法

欢迎加入我们的QQ群,无论你是否工作,学生,只要有c / vc / c++ 编程经验,就来吧!158427611 FindWindow就不说了,这说 的是另一种:GetProp 代码也差不多: 查询... HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(), GW_CHILD); while (::IsWindow(hWndPrevious)) { if (::GetProp(hWndPrevious, _FLAG)) { if (::IsI

Qt Quick 事件处理之信号与槽-2(代码备忘)

个人学习的代码来处来自:http://blog.csdn.net/foruok/article/details/30028711 1.  hello_world.qml 主要的功能是: 1. 是点击按钮,两个文本的颜色会随机变化,并输出"textFirst"的文本内容 2. 输出Text , Button , Image 三个对象的C++原型 1 import QtQuick 2.4 2 import QtQuick.Controls 1.3 3 4 Rectangle { 5 wid

【代码备忘】今天突然写的一个比较奇葩的C++ 代码,模版,friend,友元...

欢迎加入我们的QQ群,无论你是否工作,学生,只要有c / vc / c++ 编程经验,就来吧!158427611 今天突然脑袋一闪,写出这样的代码. 这样就能 不用在Ta中添加friend class , 只要实现Tb 就能访问Ta的private 属性了. 应该是比较奇葩的代码吧 ..... #include <iostream> using namespace std; template<typename T> class Ta { public: Ta(){ m_ta = 1

Matlab代码备忘

Matlab写入文件 1 set(hp1,'xdata',bbb(1,:),'ydata',bbb(2,:),'zdata',bbb(3,:)); 2 M=size(bbb,2); 3 name=strcat('laser_',num2str(i),'.txt'); 4 fid=fopen(name,'a+'); 5 for kk =1:M 6 fprintf(fid,'%g %g %g\r\n',bbb(1,kk),bbb(2,kk),bbb(3,kk)); 7 end 8 fclose(fi

nginx解析配置文件代码备忘

ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle)分配内存,每个模块一个void *指针用来指向自已需要的结构:cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)) 以上内存下传到配置解析函数:conf.ctx = cycle->conf_ctx; static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_i

php多个数组组合算法 火车头免登录发布接口代码备忘

火车头发布产品的时候,有颜色.尺码.性别等等产品属性,需要进行不重复的组合,变成不重复的数组 <?php function comb($a){ $a = array_filter($a); $out = array(); if (count($a) == 1) { $r = array_shift($a); foreach ($r as $v) $out[] = array($v); return $out; } foreach ($a as $k => $v){ $b = $a; unset

js 常用代码备忘

实现拉到底部自动加载内容: $("#picture11").scroll(function() {    var $this = $(this),    viewH = $(this).height(), //可见高度(当前div的可视高度)     contentH = $(this).get(0).scrollHeight, //内容高度(整条滚动条的高度)     scrollTop = $(this).scrollTop(); //滚动高度(被滚动隐藏起来的内容高度)