zoukankan      html  css  js  c++  java
  • do-while-zero 结构在宏定义中的应用

    do while 语句在使用宏定义时是一个有用的技巧,说明如下:
    假设有这样一个宏定义

    #define macro(condition) /
    if(condition) dosomething()

    现在在程序中这样使用这个宏:

    if(temp)
        macro(i);
    else
        doanotherthing();

    一切看起来很正常,但是仔细想想。这个宏会展开成:

    if(temp)
        if(condition) dosomething();
    else
        doanotherthing();

    这时的else不是与第一个if语句匹配,而是错误的与第二个if语句进行了匹配,编译通过了,但是运行的结果一定是错误的。
    为了避免这个错误,我们使用do{….}while(0) 把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。


    因为在C语言中对宏是不进行语法检查的,所以在替换时有可能产生一些隐蔽的错误,上面举出了一例,再举一例:

    #define INTI_RECT_VALUE( a, b )
        a = 0;
        b = 0;

    使用宏时,

    for (index = 0; index < RECT_TOTAL_NUM; index++)
        INTI_RECT_VALUE( rect.a, rect.b );

    此时,宏定义的语句并未正确的纳入for循环中,因此,在使用宏定义多条语句时,有必要加一些“封装”措施,比如我们可以这样定义,

    #define INTI_RECT_VALUE( a, b )
    {
        a = 0;
        b = 0;
    }

    但这样使用时也有一个问题,就是我们不能再宏定义语句后面自然的加一个分号,“{ } ;”的形式在语法上是错误的。而定义成do-while-zero 结构的话,就可以避免这个问题。
    所以要写一个包含多条语句的宏的话,使用do-while-zero 结构是保证安全性的一个重要技巧。


    在MISRA C-2004中,肯定了这种结构的必要性,以下是其对使用宏定义的规则:

    规则19.4 (强制): C的宏只能扩展为用大括号括起来的初始化、常量、小括号括起来的
    表达式、类型限定符、存储类标识符或do-while-zero 结构。 

    这些是宏当中所有可允许使用的形式。存储类标识符和类型限定符包括诸如 extern 、static
    和const这样的关键字。使用任何其他形式的#define 都可能导致非预期的行为,或者是非常难
    懂的代码。 
    特别的,宏不能用于定义语句或部分语句,除了do-while 结构。宏也不能重定义语言的
    语法。宏的替换列表中的所有括号,不管哪种形式的 ()、{} 、[]  都应该成对出现。 
    do-while-zero 结构(见下面的例子)是在宏语句体中唯一可接受的具有完整语句的形式。
    do-while-zero 结构用于封装语句序列并确保其是正确的。注意:在宏语句体的末尾必须省略分
    号。 






  • 相关阅读:
    使用 SVN Hook 实现服务器端代码自动更新
    在Windows下配置svn服务端钩子程序(部分)
    @RequestParam,@PathParam,@PathVariable等注解区别
    @ConditionalOnProperty 详解
    Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解
    Ajax中Delete请求参数 后台无法获取的解决方法(Restful风格)
    原生JS和jQuery版实现文件上传功能
    捡芝麻与捡西瓜
    在行动中思考
    日常相关的标准技术和组织
  • 原文地址:https://www.cnblogs.com/java20130726/p/3218640.html
Copyright © 2011-2022 走看看