GNU C 有两个扩展,它建议制作安全的宏,MAX并且MIN只对参数求值一次:typeof和__auto_type. 给出两个MAX宏的例子来演示每个宏:
#define MAX(a, b) ({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a > _b ? _a : _b; \
})
#define MAX(a, b) ({ \
__auto_type _a = (a); \
__auto_type _b = (b); \
_a > _b ? _a : _b; \
})
Run Code Online (Sandbox Code Playgroud)
对于这两个问题是,typeof并__auto_type给出错误,如果它是对位的领域。此示例代码显示了使用位字段的问题MAX:
#include <stdio.h>
#include <stdint.h>
// Insert one of the MAX macros …Run Code Online (Sandbox Code Playgroud) 在过去的几天里,我一直在学习一些 Lisp(主要是Scheme),被这些语言所提供的强大力量所吸引。当然,宏应该是这种力量所基于的最强大的功能。据我所知,学习使用宏很像首先学习如何使用一流的函数。当您学习如何使用一流函数时,它们开始适用于任何地方,以至于很难回到没有这样概念的命令式语言。例如,编写 pre-lambda Java 代码现在对我来说非常痛苦。
考虑到这种一流函数的类比,我非常震惊地发现 Lisp 宏并不是一流的。
例如,我可以通过以下方式轻松地在Scheme中使用一等函数:
(map (lambda (x) (+ x 1)) '(1 2 3))
Run Code Online (Sandbox Code Playgroud)
现在用某个宏的名称替换该 lambda,Scheme 会抱怨您正在使用宏作为变量名。鉴于我无法像数据一样传递宏,它们绝对是二等的。当然,我什至不确定随机宏在这种情况下应该如何工作,但这不是重点。
我总是对仅编译时的构造保持警惕,因为这通常表明语言存在一些限制。因此,我自然想知道宏如何成为一流的运行时对象。我们已经可以用 lambda 来做到这一点了。例如,在此方案代码中, 和 都or将eval-or打印1并返回#t,但eval-or需要在调用站点上使用撇号:
(or
(begin (display "1") (= 5 5))
(begin (display "2") (= 5 6)))
(define eval-or
(lambda (a b)
(if (eval a) #t (eval b))))
(eval-or
'(begin (display "1") (= 5 5))
'(begin (display "2") (= 5 6)))
Run Code Online (Sandbox Code Playgroud)
我不熟悉 的细节eval,但我确实知道它不保留词法范围。但也许如果我们向Scheme 添加某种特殊的构造,例如 …