首页 /  技术专区  /  C 宽屏模式 >

条件编译的书写排版

1、条件编译书写时的排版问题

1.1 什么是条件编译的排版

就是#if、#elif、#else、#endif关键字的对齐、缩进等等,这些就是“条件编译”的排版。

1.2 为什么介绍条件编译的书写排版

两个原因:

(1)写出更容易阅读的条件编译。

        与{ ... }的这种书写方式对比起来,条件编译的#if ... #endif的这种书写方式不太容易阅读,此时如果你又不注意排版问题,就会使得阅读变得很糟糕。

(2)了解了排版规则后,有利于理解别人写的条件编译

1.3 条件编译的排版

(1)条件编译没有互相嵌套时

        所有条件编译关键字语句顶格左对齐。

#if 0
...
#elif  1
...
#endif
#ifdef NUM 
..
#else 
...
#endif

(2)如果条件编译之间有嵌套时

        嵌套的条件编译需要进行缩进,如果里面有包含#define、#include的话,define、include也需要缩进。

我们举两个stdio.h中的真实案例。

1)例子1 

#if !defined __need_FILE && !defined __need___FILE
# define _STDIO_H       1
# include <features.h>

__BEGIN_DECLS 

# define __need_size_t
# define __need_NULL
# include <stddef.h>

# include <bits/types.h>
# define __need_FILE
# define __need___FILE
#endif /* Don't need FILE.  */

注意缩进方式,#是不用缩进,#和define、include中间隔有空格是没有问题的。

通过所缩进可以非常明显的看出包含关系和配对关系。

不过这个例子中没有嵌套其它的条件编译。

2)例子2

#if defined __USE_XOPEN || defined __USE_XOPEN2K8
# ifdef __GNUC__
#  ifndef _VA_LIST_DEFINED
typedef _G_va_list va_list; //正常代码(非预编译代码),不需要缩进
#   define _VA_LIST_DEFINED
#  endif
# else
#  include <stdarg.h>
# endif
#endif

这个例子中条件编译就存在非常复杂的嵌套关系,如果不进行缩进的话,你将会完全无法理清配对关系,如果无法理清配对关系,自然你也就无法理清这些条件编译的逻辑关系,阅读类似这样的源码时,你直接就发蒙了。

通过这个例子我们可以感受到,如果你不清楚条件编译的排版的话,当你看到这些玩意时会很头晕。

(3)条件编译在函数体外时

        条件编译关键字语句顶格左对齐。

Linux内核源码的例子。

1)例子1:

#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_ShortDelay(struct SiS_Private *SiS_Pr, unsigned short delay)
{
     while(delay--) {
        SiS_GenericDelay(SiS_Pr, 66);
     }
}
#endif

只有里面包含的函数代码无需缩进,正常格式写即可。

(4)条件编译在函数体内时

        没有嵌套时定格左对齐即可。

void SiS_IsVAMode(struct SiS_Private *SiS_Pr)
{
#ifdef CONFIG_FB_SIS_315
     unsigned short flag;
     if(SiS_Pr->ChipType >= SIS_315H) {
        flag = SiS_GetReg(SiS_Pr->SiS_P3d4,0x38);
        if((flag & EnableDualEdge) && (flag & SetToLCDA)) return true;
     }
#endif
     return false;
}

如果有条件编译嵌套的话,按照之前讲的进行缩进即可。

1.4 是不是学会了条件编译关键字以及排版问题,就一定能看懂源码中的条件编译了呢?

当然不是的,如果想看懂某个条件编译想干什么,还有一个关键就是要能看懂“条件编译”的判断条件。

#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
static void
SiS_WaitRetrace2(struct SiS_Private *SiS_Pr, unsigned short reg)
{
     unsigned short watchdog;
     
     watchdog = 65535;
     while((SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02) && --watchdog);
     watchdog = 65535;
     while((!(SiS_GetReg(SiS_Pr->SiS_Part1Port,reg) & 0x02)) && --watchdog);
}
#endif

想要理解条件编译#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315),你需要理解CONFIG_FB_SIS_300和CONFIG_FB_SIS_315宏。

如果想要理解这两个宏的话,这就与源码逻辑有关了。

但是#if、#ifdef等条件编译关键字,以及条件编译的排版是基础,你连这个基础都不行,想要弄懂源码中的条件编译那就更不容易了。

疑问:分析源码时,是不是源码中所有的条件编译代码都需要搞明白呢?

当然不是的,根据你自己阅读源码的需要,搞明白必须要弄明白的条件编译即可。

1.5 再说下有关条件编译的缩进

在有些源码中,条件编译缩进可能是如下样子。

#if defined __USE_XOPEN || defined __USE_XOPEN2K8
    #ifdef __GNUC__
        #ifndef _VA_LIST_DEFINED
typedef _G_va_list va_list; //正常代码(非预编译代码),不需要缩进
            #define _VA_LIST_DEFINED
        #endif
    #else
        #include <stdarg.h>
    #endif
#endif

不管是前面介绍的缩进方式,还是目前这种缩进方式,其实都可以,这两种缩进方式,不同的源码都有使用,至于我们自己使用哪种,可以跟着当前你自己所使用源码的风格走,也可以根据自己的喜好走。


头像
0/200
图片验证码