zoukankan      html  css  js  c++  java
  • 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里面是可以的,估计是用了什么奇技淫巧,没耐性看,各位大神知道的话请指点以下。
  • 相关阅读:
    ios15--综合小例子
    ios ionic 装平台 笔记
    ios14--购物车优化2
    ios13--购物车优化
    ios--plist
    ios12--简易购物车
    ios11--UIButton
    Android Json的使用(2) 使用Jackson解析和生成json
    快速Android开发系列网络篇之Retrofit
    关于XUtils框架细解
  • 原文地址:https://www.cnblogs.com/cheukyin/p/4571928.html
Copyright © 2011-2022 走看看