Answers
摘自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 }
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也是如此)
摘自《 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语言具有八进制、十进制和十六进制常量,但没有二进制常量,否则的话倒是一种更为简单的绘制图形模式的方法。