优秀的编程知识分享平台

网站首页 > 技术文章 正文

C/C++编程笔记:宏的妙用(一切为了偷懒)

nanyue 2024-08-10 18:35:45 技术文章 10 ℃

总结出自己经常重复的工作,抽象简化它们,按照适合自己思维方式,整合成我们自己需要的。
偷懒就是尽可能的少写代码,实现我们需要的效果。
前两篇究其根本也是为了能够尽可能的少写代码,从而节省时间。
一切为了偷懒 看似调侃,其实就是我的本心。** (^▽^) **
所以开始我的偷懒之旅吧!

宏的特性

宏的原样展开特性,对于才接触或者不怎么喜欢使用宏的人来说,宏一般用来定义常量或者类型,仅此而已,比如:

#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)

我的偷懒方式

1、指针、返回值检查

平常判断指针,都会类似如下方式:

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);
}

2、指针释放销毁

指针内存释放,一般用自带的 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 

3、单实例类

对于类中的一种特殊设计模式,有时候仅仅需要一个对象实例即可,可以直接简单实现如下:

#define Singleton(ClassName) \
static ClassName &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();

4、用于数组校验

对于串口、网络数据收发时,常有一些数据计算校验计算,有的是和、有的是亦或,可以简单归纳如下:

#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 calcset(arr, opt) ({ \
    uchar val = arr[0]; \
    for (int i = 1; i < arr.size(); i++) \
        val opt arr[i]; \
    val; \
})

使用方式如下:

std::veroct<uchar>  array;
...
uchar sum = calc(array, +=);
uchar xor = calc(array, ^=);

对于非 uchar 类型数据,小伙伴们是不是可以自己很容易扩展了呢!?

Tags:

最近发表
标签列表