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函数测试下效果,我就不写了,只是抛砖引玉下。

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

  • 相关阅读:
    LeetCode Array Easy 414. Third Maximum Number
    LeetCode Linked List Medium 2. Add Two Numbers
    LeetCode Array Easy 283. Move Zeroes
    LeetCode Array Easy 268. Missing Number
    LeetCode Array Easy 219. Contains Duplicate II
    LeetCode Array Easy 217. Contains Duplicate
    LeetCode Array Easy 189. Rotate Array
    LeetCode Array Easy169. Majority Element
    LeetCode Array Medium 11. Container With Most Water
    LeetCode Array Easy 167. Two Sum II
  • 原文地址:https://www.cnblogs.com/sinpo828/p/10785636.html
Copyright © 2011-2022 走看看