C语言基础:do{...}while(0)的使用

        工程开发中,尤其阅读代码时,有时会碰到一些让我们内心"嗯哼"一下的代码。比如:


#define Call_Mcal_DmaMux_Init(u32ptr) \
do \
{ \
Mcal_Trusted_Call1param(Mcl_DmaMux_Init,(u32ptr)); \
} \
while(0)

        如上的宏定义,是否能理解?本文,我们就聊聊宏定义与do{...}while(0)的结合。

1、宏的使用

        开发中,宏的使用很频繁。为了精简代码的编写过程,有时,我们会将多条语句用一个宏表示。

示例 1

#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL()  do { \
  if (tcpip_try_callback(pbuf_free_ooseq_callback, NULL) != ERR_OK) { \
      SYS_ARCH_PROTECT(old_level); \
      pbuf_free_ooseq_pending = 0; \
      SYS_ARCH_UNPROTECT(old_level); \
  } } while(0)

示例 2


#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
    if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \
      IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
    } else { \
      IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
    } } while(0)

        熟悉Lwip(Light Weight (轻型)IP协议)的小伙伴,应该比较熟悉上述两个示例。在Lwip中,会经常看到宏定义do{...}while(0)的结构。如上示例可以看出,使用宏替换多条语句,会方便的多。但是,为什么要使用do{...}while(0)这样的结构形式呢?:使用do{...}while(0)构造后的宏定义,可避免大括号、分号等的影响。有点难以理解是吗?看一个例子消化一下。

(一)不用do{...}while(0)结构进行宏定义带来的影响

        示例:定义宏Get_OptResult(a, b, c, d)精简代码c = ((a) + (b));和d = ((a) * (b));,如下所示:


#include <stdio.h>

#define Get_OptResult(a, b, c, d) \           
         c = ((a) + (b)); \
         d = ((a) * (b));                             

int main(void)
{
  int JudgeFlag = 0;
  int cResult, dResult;
  
  if(JudgeFlag == 0)
      Get_OptResult(60, 20, cResult, dResult);
  else
  {
    cResult = 100;
    dResult = 1000;
  }

    printf("cResult = %ld, dResult = %ld.\n", cResult,dResult );

    getchar();
}

        如上代码有什么问题呢?宏展开以后,如下所示:

#include <stdio.h>

#define Get_OptResult(a, b, c, d) \           
         c = ((a) + (b)); \
         d = ((a) * (b));                             

int main(void)
{
  int JudgeFlag = 0;
  int cResult, dResult;
  
  if(JudgeFlag == 0)
         c = ((a) + (b));
         d = ((a) * (b));;
  else
  {
    cResult = 100;
    dResult = 1000;
  }

    printf("cResult = %ld, dResult = %ld.\n", cResult,dResult );

    getchar();
}

        在Line14处,分号";"这将会带来什么影响呢?:else语句永远不会被执行,此时,else没有对应的if,编译器可能会报语法错误,如下所示:

        面对这个问题,怎么办呢?:使用do{...}while(0),吸收分号";"带来的影响。

(二)使用do{...}while(0)结构进行宏定义


#include <stdio.h>

#define Get_OptResult(a,b,c,d) do {\           
         c = ((a) + (b)); \
         d = ((a) * (b)); \
         }while(0)

int main(void)
{
  int JudgeFlag = 0;
  int cResult, dResult;
  
  if(JudgeFlag == 0)
      Get_OptResult(60, 20, cResult, dResult);
  else
  {
    cResult = 100;
    dResult = 1000;
  }

    printf("cResult = %ld, dResult = %ld.\n", cResult,dResult );

    getchar();
}

        宏展开,如下所示:


#include <stdio.h>

#define Get_OptResult(a,b,c,d) do {\           
         c = ((a) + (b)); \
         d = ((a) * (b)); \
         }while(0)

int main(void)
{
  int JudgeFlag = 0;
  int cResult, dResult;
  
  if(JudgeFlag == 0)
    do{
         c = ((a) + (b));
         d = ((a) * (b));
    }while(0);
  else
  {
    cResult = 100;
    dResult = 1000;
  }

    printf("cResult = %ld, dResult = %ld.\n", cResult,dResult );

    getchar();
}

        如上,使用do{...}while(0)结构,宏展开以后,吸收了分号";"带来的影响,进而确保else语句可以被执行到。

        综上,在使用宏定义多条语句时,do{...}while(0)结构不妨一试。

猜你喜欢

转载自blog.csdn.net/jk_101/article/details/128784310