首页 > 有哪些不能更赞的宏定义?

有哪些不能更赞的宏定义?

之前看到这个问题只是在 C/C++ 方面的,现在不限语言,大家都来说说自己见过哪些很赞的宏定义。


摘自linux/net/core/skbuff.c:
简洁有效。

646 static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
 647 {
 **648 #define C(x) n->x = skb->x**
 649 
 650     n->next = n->prev = NULL;
 651     n->sk = NULL;
 652     __copy_skb_header(n, skb);
 653 
 654     C(len);
 655     C(data_len);
 656     C(mac_len);
 657     n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
 658     n->cloned = 1;
 659     n->nohdr = 0;
 660     n->destructor = NULL;
 661     C(tail);
 662     C(end);
 663     C(head);
 664     C(data);
 665     C(truesize);
 666     atomic_set(&n->users, 1);
 667 
 668     atomic_inc(&(skb_shinfo(skb)->dataref));
 669     skb->cloned = 1;
 670 
 671     return n;
 672 #undef C
 673 }

tree.h
libuv中的代码(应该也是第三方拷贝过来的), 整个文件全部是宏实现, 实现了2个数据结构SPLAY_TREE, RB_TREE


GLUT的回调,直接输入函数名就行,简直像Lisp


不管哪种语言都不赞成用宏——C 除外,因为相比之下 C 的语法太受限了。


clojure.core里面有一个pipeline宏是这样的 ->
用法如下

    (-> a f0 (f1 b) (f2 c d) f3 ....)

会被展开为

   (...(f3 (f2 (f1 (f0 a) b) c d))...)

这个非常好用。

另外有一个宏叫if-let

(if-let [x (get-something...)]
   (f x) (g))

展开之后变成

(let [x (get-something...)]
  (if x (f x) (g)))

如果用命令式的方式语言来写,可能像是这样的:

if-let (x=get-something(...))
    f(x); 
else
    g();

展开为

x = get-something(...);
if (x) f(x); else g();

另外,我公司的项目里面也有很多精彩的宏,比如这个:

(defmacro spy [body]
  `(let [ret# (try ~body
                   (catch Exception e#
                     (do
                       (println "\033[33;1mSpy Result in" ~(str *ns*) "\033[0m\n "
                                "\033 36;1m" ~(pr-str body) "\033[0m"
                                "\n\033[35;1m has thrown an Exception\033[m\n")
                       (clojure.stacktrace/print-cause-trace e#))))]
     (println "\n\033[33;1mSpy Result in" ~(str *ns*) "\033[0m\n "
              "\033[36;1m" ~(pr-str body) "\033[0m"
              "\n\033[35;1m=>" (pr-str ret#) "\033[0m\n")
     ret#))

这个起到的作用是,在程序运行时、不影响程序工作(不影响任何函数的返回值)的情况下,把标记了spy的代码的所在命名空间、源代码和这段代码在当前运行时的返回值实时输出在屏幕上。

而有另外一个宏叫做with-spy,这个宏后面指定一系列已经存在函数的函数名,那么在这个宏之内每次调用这些函数,都会触发spy

当然还有deep-spy宏,会级联地spy所标记部分的代码中所有的执行过程。

另外,clojure里面的case(相当于命令式语言的switch-case结构)、cond(case的条件式扩展,通过断言而不是值来判定选择树)、doseq迭代器(相当于其他语言的foreach)、for迭代生成器、用来定义函数的defn(没错,相当与js里面的function xxx (...) )全都是宏——而不是写死在编译器里的——这使得clojure只有十几个基本元(公理),而基本元之外的整个clojure语言内核都是直接由clojure自身的代码构成的(这不是用c写gcc,而是——比如用clojure1.7的一部分构建出clojure1.7的另一部分——而保持版本号不变——其他lisp也是如此)


#define LOG(level, format, ...) \
    do { \
        fprintf(stdout, "[%s|%s@%s,%d] " format "\n", \
                level, __func__, __FILE__, __LINE__, ##__VA_ARGS__ ); \
    } while (0)

摘自《C专家编程》 (如果你正在学习C/C++,建议你多读几遍这本书。网上有电子版,我就不给链接了。)


根据位模式构建图形图标(icon)或者图形(glyph),是一种小型的位模式映射于屏幕产生的图像。一个位代表图像上的一个像素。如果一个位被设置,那么它所代表的像素就是“亮”的。如果一个位被清除,那么它所代表的像素就是“暗”的。所以,一系列的整数值能够用于为图像编码。类似Iconedit这样的工具就是用于绘图的,他们所输出的是一个包含一系列整型数的ASCII文件,可以被一个窗口程序所包含。它所存在的问题是程序中的图标只是一串十六进制数。

在C语言中,典型的16X16的黑白图形可能如下:

static unsigned short stopwatch[] = {
0x07C6,
0x1FF7,
0x383B,
0x600C,
0x600C,
0xC006,
0xC006,
0xDF06,
0xC106,
0xC106,
0x610C,
0x610C,
0x3838,
0x1FF0,
0x07C0,
0x0000
};

正如所看到的那样,这些C语言常量并未有提供有关图形实际模样的任何线索。

这里有一个惊人的#define定义的优雅集合,允许程序建立常量使它们看上去像是屏幕上的图形。

#define X )*2+1
#define _ )*2
#define s ((((((((((((((((0 /* For building glyphs 16 bits wide */

定义了它们之后,只要画所需要的图标或者图形等,程序会自动创建它们的十六进制模式。使用这些宏定义,程序的自描述能力大大加强,上面这个例子可以转变为:

static unsigned short stopwatch[] =
{
s _ _ _ _ _ X X X X X _ _ _ X X _ ,
s _ _ _ X X X X X X X X X _ X X X ,
s _ _ X X X _ _ _ _ _ X X X _ X X ,
s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
s _ X X _ _ _ _ _ _ _ _ _ X X _ _ ,
s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ _ _ _ _ _ _ X X _ ,
s X X _ X X X X X _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
s X X _ _ _ _ _ X _ _ _ _ _ X X _ ,
s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
s _ X X _ _ _ _ X _ _ _ _ X X _ _ ,
s _ _ X X X _ _ _ _ _ X X X _ _ _ ,
s _ _ _ X X X X X X X X X _ _ _ _ ,
s _ _ _ _ _ X X X X X _ _ _ _ _ _ ,
s _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
};

显然,与前面的代码相比,它的意思更为明显。标准的C语言具有八进制、十进制和十六进制常量,但没有二进制常量,否则的话倒是一种更为简单的绘制图形模式的方法。

【热门文章】
【热门文章】