日复一日,年复一年的“码砖”是一件极其枯燥乏味的事情。我们应该将经历放在更有趣的地方,去攻克我们前进路上的障碍。将重复无意义的“码砖”进行总结提炼,变成我们自己的轮子。
而这一想法老早就在我心中,在此抛砖引玉,希望有人有更好的建议。
在本场 Chat 中,会讲到如下内容:
适合人群: 对 C/C++ 有一定基础且有兴趣的技术人员
总结出自己经常重复的工作,抽象简化它们,按照适合自己思维方式,整合成我们自己需要的。偷懒就是尽可能的少写代码,实现我们需要的效果。所以开始我的偷懒之旅吧!
宏的原样展开特性,对于才接触或者不怎么喜欢使用宏的人来说,宏一般用来定义常量或者类型,仅此而已,比如:
#define PI 3.1415926#define unsigned char uchar
或者实现一些简单的函数功能,因为没有类型,有时候类似模板一样,可以输入使用不同类型的参数,比如:
#define add(x,y) (x+y)#define sub(x,y) (x-y)#define mul(x,y) (x*y)#define dev(x,y) (x/y)
标准输出方式:
int delay = 5;std::cout << "delay:" << delay << std::endl;
最简单的宏实现方式就是:
#define logs(x) std::cout << #x":" << x << std::endl;int delay = 5;logs(delay);
扩充显示文件名、函数、行号方式
#define FILE_INFO "[" << __FILE__ << '@' << __FUNCTION__ << '#' << __LINE__ << "]"#define logs(x) std::cout << FILE_INFO << #x":" << x << std::endl;int delay = 5;logs(delay);
对于多变量的,形如 logs(a,b,c,d) 将在另一篇 《一个极简便跨平台的 C++ 日志输出工具分享》 中详细展开讲解,希望有兴趣的小伙伴关注。
指针、返回值检查
平常判断指针,都会类似如下方式:
int ret = 3;int *ptr = &ret;if (ret == -1) return; if (ptr == NULL) return;
可能带打印且有返回值,便于快速分析:
int ret = 3;int *ptr = &ret;if (ret == -1){ std::cout << "ret:" << ret << std::endl; return; }if (ptr == NULL){ std::cout << "ptr:" << ptr << std::endl; return false; // 或者 -1}
可以如下实现:
#define check(var, value, ...) \ if (var == value) {\ logs(var);\ return __VA_ARGS__;\ }void test1() // 无返回值{ int ret = 3; int *ptr = &ret; check(ret , -1); check(ptr, NULL);}int test2() // 有返回值{ int ret = 3; int *ptr = &ret; check(ret, -1, 0); check(ptr, NULL, false);}
指针内存释放,一般用自带的 delete 或者有自己的释放函数,假设如 free(),则方式如下:
xxx *ptr = new xxx;...if (ptr != NULL){ delete ptr; // or free(ptr); ptr = 0;}
则可简单如下定义:
#define delptr(ptr) if (ptr) {delete ptr; ptr = 0;}#define freeptr(fun, ptr) if (ptr) {fun(ptr); ptr = 0;}
对于集合型指针,则可直接如下定义:
#define delptrlist(list) for (int i = 0; i < list.size(); i++) delete list[i]; list.clear();#define delptrset(list, type) foreach (type p, list) delptr(p); list.clear();#define delptrset11(list) foreach (auto p, list) delptr(p); list.clear(); // 版本 >= c++11
对于类中的一中特殊设计模式,有时候仅仅需要一个对象实例即可,可以直接简单实现如下:
#define Singleton(ClassName) \static ClassName &instance() {\ // instance() 返回的是引用,可以用 "." 运算符,比指针 “->” 少。 (^▽^) static ClassName *m_instance = 0;\ if (m_instance == 0)\ m_instance = new ClassName;\ return *m_instance;\}
在对需要单实例的类加上如下设置即可:
class CTest{public: Singleton(CTest) // 添加单实例宏 ~CTest(); void xxxx(); void yyyy();private: CTest();};// 使用方式如下:CTest::instance().xxxx(); CTest::instance().yyyy();// 更简洁的使用形式如下:#define ctest CTest::instance()ctest.xxxx();ctest.yyyy();
对于串口、网络数据收发时,常有一些数据计算校验计算,有的是和、有的是亦或,可以简单归纳如下:
#define calc(dat, len, opt) ({ \ uchar val = dat[0]; \ for (int i = 1; i < len; i++) \ val opt dat[i]; \ val; \})// 使用方式如下:uchar dat[30];...uchar sum = calc(dat, 30, +=);uchar xor = calc(dat, 30, ^=);
如果是集合,向量等形式,可以修改如下:
#define calc(arr, opt) ({ \ uchar val = arr[0]; \ for (int i = 1; i < arr.size(); i++) \ val opt arr[i]; \ val; \})// 使用方式如下:std::veroct array;...uchar sum = calc(array, +=);uchar xor = calc(array, ^=);
对于非 uchar 类型数据,小伙伴们是不是可以自己很容易扩展了呢!?
由于受到工作方向的影响,有很多用法被局限在我们日常的工作方向中,不能很好的做出符合大家各自场景的东西。然而我觉得学习,除了学到东西,更应该获取的是思维方式。
我的砖就抛到这里,希望对你们有用。(大牛请高抬贵脚,不喜勿踩 (^▽^) )
接下来的路就请各位小伙伴们自己走了!
阅读全文: http://gitbook.cn/gitchat/activity/5f24cd1d007b9367eec77f20
您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。