C宏系统缺陷

这两天稍稍看了一下boost的preprocessor库,发觉boost那帮疯子竟然利用各种奇技淫巧定义出各种数据类型和结构,还在上面定义出加减乘除等等各种运算,在快速浏览的过程中,还瞄到了很眼熟的各种宏名:list,cons,fold_left、fold_right,估计这帮人把函数式语言的很多特性也搬上去。

本着造轮子练本领的原则,我也尝试自己去实现各种元素,可是智商不够,越写越难受,最后无疾而终。

大致总结了一下,暂时发现C的宏有以下反直觉的缺点:

1、无法定义局部变量,所有宏必须在最外层定义,致使全局可见

而且没有类似namespace的功能,命名时超头疼

不支持多行出写,若要多行需在每行末端加 "\"

2、无控制流,要实现循环、选择非常麻烦

3、传参机制反直觉,正常语言的传参一般采用应用序,先完全展开参数再传入,而C的宏参数展开过程中若遇到#或##就停止展开,如:

1      #define BOOL(n)      BOOL##n
2      #define BOOL0         0
3      #define BOOL1         1
4      #define BOOL2         1
5      #define BOOL3         1

BOOL(n)可获取值n的真假值

1 #define IF(c, x, y)       IF##c(x, y)
2 #define IF0(x, y)         y
3 #define IF1(x, y)         x

上面的宏是想要实现选择控制,IF中传入逻辑值c,若c为0则返回y, 若c为1则返回x

假如按如下调用:  IF( BOOL(3),  "t", "f" ),按直觉此句应生成“t”,

可事与愿违,   因为展开BOOL(3)时碰到##,所以直接返回BOOL3,

结果上面的宏就变成了 IF( BOOL3,  "t", "f"),按IF宏体继续展开, 则变成了 IFBOOL3("t", "f")

最后预处理器报错: 找不到IFBOOL3

因此,为了能正确地把参数BOOL(3)展开为1,还需要多包装多一层宏:

1 #define IF(c, x, y)       IF_C(c, x, y)
2 #define IF_C(c, x, y)   IF##c(x, y)

这样,IF( BOOL(3),  "t", "f" )就会先展开参数,变成 IF( BOOL3,  "t", "f"),

然后宏体展开, IF_C( BOOL3, "t", "f" ),展开参数成了, IF_C( 1, "t", "f" ),

最后才会正确地展开成 IF1( "t", "f" )

4、缺少整数类型,若要利用计数器循环生成代码时非常麻烦,首先要自己手工定义一堆整数的INC:

1       #define INC_0 1
2         #define INC_1 2
3         #define INC_2 3
4         #define INC_3 4
5         ……………
6
7         #define DEC_x x
8         ………………

然后再在INC_xx和DEC_xx之上定义加法,减法,

这样做相当于需要手工利用最基本的元素构造基本方法,再将这些基本方法不停地复合嵌套,抽象出更高阶的函数,

工作量跟创造语言差不多

本来创造语言还是挺有趣的一件事,可由于刚刚提过的反人类反直觉的古怪传参机制的存在,

致使复合方法构造高阶函数的过程异常痛苦,得不时留意参数展开时会不会被#和##打断,若被打断则需要增加一层宏来继续展开。

5、无法实现递归,如:

1    #define x y+1
2      #define y x+1

则展开x时,先展开成y+1,继续展开y,x+1+1,这时又碰到了x,预处理器便停止展开了。

无法实现递归,那利用宏实现循环时就变得异常冗长了。

一般来说,while循环和尾递归是等价的,所以若支持递归,则可用尾递归的形式实现循环,但现在不支持,

所以我们需要把尾递归的每一步都得亲自展开,并将其手工显示的定义成宏,如:

1         #define WHLE(...)       WHILE##n(...)
2         #define WHILE0(...)     xxxxx
3         #define WHLE1(....)     WHILE0(......)
4         #define WHLE2(....)     WHILE1(......)
5         #define WHLE3(....)     WHILE2(......)
6         ...................  

这样做不仅麻烦,而且递归深度也只能是一个固定值

6、c的宏只是作简单的文本替换,所以替换到文本后可能会出现,下面就是一个最经典的例子:

1       #define square(x)  x*x
2       cout<<square(2+3)<<endl;

替换后就变成了2+3*2+3,所以写宏时还要注意在必要的地方加括号。。。。。。。。。

7、没办法传function-like macro的名字,如:

1         #define ADD(n, m)   ..........
2         #define FOR(k, op,...)  ......

若调用FOR((3,3), ADD,...),想要在FOR内部ADD(3,3),发现预处理器会报错,说ADD没定义。

也就是说函数名不能当参数传入,当然我发现boost里面是可以的,估计是用了什么奇技淫巧,没耐性看,各位大神知道的话请指点以下。

时间: 2024-10-12 13:23:55

C宏系统缺陷的相关文章

【2018.10.11 C与C++基础】C Preprocessor的功能及缺陷(草稿)

一.前言及参考资料 C Preprocessor即所谓的C预处理器,C++也继承了C的预处理程序,但在C++语言的设计与演化一书中,C++的设计者Bjarne Strustrup提及他从未喜欢过C预处理器,认为C预处理器尤其是其中的宏定义存在许多缺陷,破坏了程序设计语言的类型系统及变量的作用域边界等等,但是语言设计者却很难为预处理中的各种功能找到具有更好结构而又高效的替代品. 我们知道在编译C/C++程序时,一般会经过预处理.编译.汇编.链接这四个阶段. 其中预处理在编译过程中发挥着不可替代作用

读书笔记--C陷阱与缺陷(七)

第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一种判断编译器如何处理内存0的代码: 1 #include <stdio.h> 2 int main() 3 { 4 5 char *p; 6 p=NULL; 7 printf("location 0 contains: %d\n", *p); 8 9 return 0; 10

为什么Javascript有设计缺陷

1. 设计阶段过于仓促 Javascript的设计,其实只用了十天.而且,设计师是为了向公司交差,本人并不愿意这样设计(参见<Javascript诞生记>). 另一方面,这种语言的设计初衷,是为了解决一些简单的网页互动(比如,检查"用户名"是否填写),并没有考虑复杂应用的需要.设计者做梦也想不到,Javascript将来可以写出像Gmail这种极其庞大复杂的网页. 2. 没有先例 Javascript同时结合了函数式编程和面向对象编程的特点,这很可能是历史上的第一例.而且直

实验六:Bookstore项目测试缺陷报告

一.                 Bookstore项目测试缺陷报告 缺陷编号 01.01.0001 发现人 林臻 记录日期 2016-06-12 所属模块 购物车模块 确认人 林臻 确认日期 2016-06-12 当前状态 公开 严重度 3 优先级 3 问题概述 用户在加入购物车添加数量为0时,点击购买也能添加进购物车. 问 题 再 现 描 述 登录用户,选择图书分类,; 选择图书C++购买数量为1 ,查看购物车已添加; 选择图书Oracle购物数量为0,购买,查看购物车,书籍已添加; 图

第六次作业:购物系统缺陷

缺陷编号:01.01.0001       发现人:游志昌   记录日期:2016-06-10 所属模块:购物车          确认人:xxx    确认日期:2016-06-10 当前状态:公开            严重度 2        优先级 2 ------------------------------------------------------------------------ 问题概述:用户后将物品添加到购物车,在结算的时候还要进行用户登录 -------------

Bookstore测试缺陷报告

缺陷编号 01.01.0001 发现人 FHW 记录日期 2016-6-12 所属模块 用户注册 确认人 FHW 确认日期 2016-6-12 当前状态 公开 严重度 2 优先级 1 问题概述:注册新用户时,没有输入密码也可注册成功 问题再现描述:1.用户执行注册操作 2.在用户注册界面,输入想要账户名(如: FHW): 3.按回车键显示:注册成功(应该出现:注册失败,请输入您的密码). 问题隔离描述: 1. 重复注册用户操作,问题依然存在. 2.输入密码也可以成功注册(正确操作) 日志: 20

第四次博客作业:bookstore缺陷报告

Bookstore系统集成测试缺陷报告 ------------------------------------------------------------------------------------------------------------------ 缺陷编号:01.01.01             发现人:林怡            记录日期:2016-06-12 所属模块:购物车                 确认人:林怡            确认日期:2016-06

bookstores网上书店测试缺陷报告1

Bookstore网上书店系统测试缺陷报告   缺陷编号 01.01.0001 发现人 吴赵昕 记录日期 2016-06-10 所属模块 购物车 确认人 吴赵昕 确认日期 2016-06-10 当前状态 公开 严重度 3 优先级 3 问题概述 购物车中添加两个书目及以上时进行更新操作出现未捕捉到的异常 问 题 再 现 描 述 添加一个书目a到购物车(例C使用教程). 添加一个不同于a的书目b到购物车(例JavaEE基础实用教程). 在购物车中对任意书目进行更新操作. 问题隔离描述 重复添加书目a

bookstore网上书店测试缺陷报告2

Bookstore网上书店系统测试缺陷报告   缺陷编号 01.01.0002 发现人 吴赵昕 记录日期 2016-06-10 所属模块 购物车 确认人 吴赵昕 确认日期 2016-06-10 当前状态 公开 严重度 3 优先级 3 问题概述 不同用户登陆后共享同一个购物车 问 题 再 现 描 述 登录用户a,查看购物车内容; 登录用户b,查看购物车内容; 在用户b下往购物车添加书目; 登录用户a,发现购物车内容与用户b购物车内容相同. 问题隔离描述 重复登录不同用户,并且更新书目,问题依然.