zoukankan      html  css  js  c++  java
  • C/C++ 宏操作小技巧

     Abstract

    之前写了一个非常mini的log库(也不算库把,自己瞎jb写的),里面几乎都是宏的实现。这里打算趁热打铁,把自己知道的几下子都贴出来,后续如果有新的收获会更新这个博文。

    文笔拙劣,主要是给自己做个提醒。

    1. 运行时检测大小端

    一目了然,不做解释。

    #define __ENDIAN() ({ 
            short _a = 0x1234; 
            *((char*)&_a) == 0x12 ? 1 : 0; 
        })
    #define big_endian()  (__ENDIAN() == 1)
    #define little_endian()  (__ENDIAN() == 0)
    

     当然还有另一种方式去确定字节序。下面是编译时确定字节序的方式。

    只要通过引入头文件<endian.h>便可以在编译时通过宏判断字节序了。参考 ‘/usr/include/linux/tcp.h’ 你会发现另一种写法(自己去看下)。

    #if __BYTE_ORDER == __LITTLE_ENDIAN
        // do_sth();
    #elif __BYTE_ORDER == __BIG_ENDIAN
        // do_sth();
    #else
    #error "Unknown byte order"
    #endif
    

    2. max函数与min函数

    max与min函数是最常用的。我们可以有很多方式去实现它,宏,inline,函数等。

    由于这两个函数都很小,一般不建议

    #define max(a, b) ({ 
            typeof(a) _a = a; 
            typeof(b) _b = b; 
            _a >= _b ? _a : _b; 
        })
    

    3. SDK 中的函数名拼接

    #include <stdio.h>
    
    #define test(__DOC, args) __SDK_##__DOC##_TEST(args)
    void __SDK_V1_TEST(int a) {
        fprintf (stdout, "version %d
    ", a);
        return;
    }
    
    void __SDK_V2_TEST(int a) {
        fprintf (stdout, "version %d
    ", a);
        return;
    }
    
    int main(int argc, char **argv) {
        test(V1, 1);
        test(V2, 2);
        return 0;
    }
    

     4. 获取枚举变量的名字

    枚举定义通常具有更好的可读性, 比如

    enum enWeek_t {MONDAY, TUESDAY};

    中MONDAY与TUSDAY比枚举值0,1有更好的可读性。事实上对于开发者,一个可读性更好的名称比这个名称的实际值加友好。如果是日志上能给出‘MONDAY’而不是 0这样的字眼,更能帮助我们理解。所以获取枚举类型的名称或许是个更好的选择。

    一个示例:

    enum_name.h

     1 #ifndef __ENUM_NAME_H__
     2 #define __ENUM_NAME_H__
     3 
     4 // MACRO_HELPER 
     5 #define MACRO_HELPER(v) v,
     6 
     7 #define WEEKDAYS 
     8     MACRO_HELPER(MONDAY)
     9     MACRO_HELPER(TUESDAY)
    10     MACRO_HELPER(WEDNESDAY)
    11 
    12 // 这里宏替换会换成 enum {MONDAY, TUESDAY, WEDNESDAY,};
    13 enum {
    14     WEEKDAYS
    15 };
    16 #undef MACRO_HELPER(v)
    17 #endif //__ENUM_NAME_H__

    enum_name.c

     1 #include "enum_name.h"
     2 
     3 // 这里重新定义宏,利用编译器的特性 #v会把v原封不动的保存为一个字符串类型(## 两个#才是拼接,参考上一篇log函数的实现)
     4 #define MACRO_HELPER(v) {v, #v},
     5 struct week_name_t {
     6     int val;
     7     const char *name;
     8 }; // 结构体的定义中成员顺序,必须和宏的定义一致
     9 
    10 // 这里宏会替换成 struct week_names[] = {
    11 // {MONDAY, "MONDAY"}, {TUESDAY, "TUESDAY"}, {WEDNESDAY, "WEDNESDAY"}, {0, 0}}
    12 struct week_names[] = {
    13     WEEKDAYS
    14     {0, 0}    // this is the end of array
    15 };
    16 
    17 const char *get_enum_name(int v) {
    18     int idx = 0;
    19     while (week_names[idx].name) {
    20         if (idx == v)
    21             return week_names[idx].name;
    22     }
    23     return "Unknow";
    24 }

    这里我们对外的唯一接口就是 get_enum_name 这个函数,只需要传入指定的数值,我们就能获得对应星期的名字。主要依赖宏替换的效果,如果想追加‘星期四’, ‘星期五’,我们只需要在头文件的 WEEKDAYS 添加 MACRO_HELPER(THURSDAY) 与 MACRO_HELPER(FRIDAY) 就行了,不要要其他的变动。接下来可以写个main函数测试下效果,我就不写了,只是抛砖引玉下。

    当然你也可以编写一个函数把所有星期的名称字符串对应输出,这是你的自由,不在这个博问的讨论范围。

  • 相关阅读:
    模板笔记2
    模板笔记
    qt打包可执行文件
    合并单独的视频和音频
    模板1
    mysql 数据表中查找重复记录
    mysql左连接右连接(查询两张表不同的数据)
    mysql--构造数据、导入导出
    mysql安装
    linux下启动tomcat服务
  • 原文地址:https://www.cnblogs.com/sinpo828/p/10785636.html
Copyright © 2011-2022 走看看