`
he91_com
  • 浏览: 370743 次
文章分类
社区版块
存档分类
最新评论

“#if 0/#if 1 ... #endif”的注释作用

 
阅读更多

1、先说“#if 0/#if 1 ... #endif”的作用,楼上诸位或多或少都说到了一点,但都没有说到关键的地方。我们知道,C标准不提供C++里的“//”这样的单行风格注释而只提供“/* */”这样的块注释功能,我们通常使用它写代码中说明性的注释文字(注释作用)以及在调试时关闭某段代码对编译器的可见性(屏蔽作用),当然,这里所谓的“注释作用”和“屏蔽作用”是我们从功能上下的主观定义,对预处理器而言,两者并无任何区别。对于前者,因为“注释”中不会再出现“注释”和“需要屏蔽的代码段”,所以不会有嵌套的需求,所以通常不会有问题;而对于后者,当我们在调试程序时需要“屏蔽”某段代码时,该段代码中可能包含着前述的“注释”和/或“已被屏蔽的代码段”,这时就产生了“/* */”嵌套使用的需求,但SB的C标准恰恰不允许我们这么干。当你试图使用嵌套的块注释功能时,会发现预处理器把最外层注释的开始和最内层注释的结尾这两者之间的内容处理成了注释,而其后一直到最外层注释结尾的内容被当作了“有效代码”——这显然会引起若干语法错误而导致编译中止。高手们开动脑筋想到了“#if 0 ... #endif”,它同样由预处理器进行处理,同样可以“屏蔽”一段代码,你想把说明文字写在里面也可以,这些和“/* */”都一样,但不一样的是:第一它允许嵌套(层数上限由预处理器决定)、第二你随时可以把“#if 0”改成“#if 1”来取消对某段代码的“屏蔽”——很卓越的特性,快抛弃笨拙的“/* */”吧!它唯一的缺点就是在编辑器中没有“注释”该有的文本显示样式。

2、现在再来说说2楼提到的自动变量局部化的问题:
------------------------------------------------
通过google,得知:

#if 0
code
#endif



(1)code中定义的是一些调试版本的代码,此时code完全被编译器忽略。如果想让code生效,只需把#if 0改成#if 1
(2)#if 0还有一个重要的用途就是用来当成注释,如果你想要注释的程序很长,这个时候#if 0是最好的,保证不会犯错误。(但是林锐的书上说千万不要把#if 0 来当作块注释使用)
#if 1可以让其间的变量成为局部变量。
(3)这个结构表示你先前写好的code,现在用不上了,又不想删除,就用这个方法,比注释方便。
------------------------------------------------

通过我上面说的第一点,我们可以知道,对“#if/#endif”的处理是预处理器完成的,而预处理器的唯一工作就是作“文字替换”的“预处理”工作,它并不负责常数符号表的生成、变量存储空间的分配、代码的重定位等工作,那么完全是给预处理器看的“#if/#endif”怎么能控制变量的生存期、怎么能决定变量可以在哪里定义??
打开编辑器,写下如下代码:

复制代码
===========================
volatile unsigned char a;
unsigned
int main(void)
{
a
= 0;
#if 1
unsigned
char *p = &a;
*p = 255;
#endif
return 0;
}
===========================
复制代码


存成.c文件后用任何C编译器(不包括C++编译器)编译,都会在红字那一行报错——为什么呢?因为预处理器进行“预处理”的时候发现if的条件表达式为“真”,所以它把那段代码块留下了,而只把代码块前后的“预处理指示符号(或者叫做预处理命令)”给清除掉了,这样,预处理后的结果交给编译器“翻译”的时候,它发现在一个函数(在这里为main函数)内部的表达式语句(在这里是a = 0;)之后发现了变量声明/定义语句(在这里是声明并定义指针变量p的语句)——按照编译器的规则,这是一个错误,所以它拒绝接受这样的输入、并开始抱怨(中止编译、给出错误信息)。

至此,关于“#if 1/#if 0/#endif”,我要说的就全说完了,欢迎大家拍砖哈~_~


下面再多啰嗦两句。
--------------------------
那么我们能不能享受C++程序员所得到的“将变量的定义放在它开始被需要的地方”这种待遇呢?
答案是肯定的。
手段?
——代码块!

  用一对大括号括起来的代码块的首部,可以声明/定义变量,这些变量的作用域仅限于该代码块内部,当然,这些变量声明/定义语句也必须全部位于该代码块中第一个表达式语句之前,不然会出现上面描述的错误,不过好在C编译器允许我们在代码块中嵌套定义代码块,所以大家从现在开始,大可不必在函数的开头定义一大堆变量,那里只要写一些在整个函数执行过程当中都需要的变量的声明/定义语句就好了;至于循环结构的循环变量等这些生存期不长的变量,它们的声明/定义语句完全可以放在一个用一对大括号括起来的代码块的首部。
  啰嗦了这么多,写一小段代码证明一下我的说法,呵呵:

复制代码
===========================
volatile unsigned char a;
unsigned
int main(void)
{
a
= 0;
{
//
unsigned char *p = &a;
*p = 255;
}
return 0;
}
===========================
复制代码


  注:我个人的代码书写风格是大括号独占一行并且缩进量与父语句相同,函数体、循环体、case、if四者中的语句增加缩进,但如上的“代码块”则不增加。
存盘、编译。
Hmmmm,编译器不再在红色的行给出错误提示了,编译通过,得证~_~

分享到:
评论

相关推荐

    PC-Lint报错详解(中文版)

    -1―未关闭注释 (位置) 文件结束的时候,仍然有一个未关闭的注释存在,打开的这个注释位置将被显示出来。 ―2―未关闭的引号 在行尾的时候,仍然存在一个同行的未关闭的引号(单引号或双引号)。 -3-#else 没有一...

    ifdef-loader:用于JavaScriptTypeScript条件编译的Webpack加载器

    ifdef-loader Webpack加载器,可直接从Webpack进行JavaScript或TypeScript条件编译( #if ... /// #if PRODUCTION && version.charAt(0)=='X' console . log ( "Ho!" ) ; /// #endif 如果表达式为true ,则包括#if和#

    soureinsight4 添加注释

    ctrl+/ ctrl+3 chrl+8 依次添加注释// /*****/ #if0 #endif 实测可用

    uboott移植实验手册及技术文档

    #cd ../../include/configs #cp smdk2410.h fs2410.h 退回 U-Boot根目录:#cd ../../ (4)建立编译选项 #vi Makefile smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3...

    C# 使用方法 入门教程

    2.13.2 #if, #elif, #else和#endif. 62 2.13.3 #warning和# error. 63 2.13.4 #region和#endregion.. 63 2.13.5 #line.. 64 2.13.6 #pragma.. 64 2.14 C#编程规则...... 64 2.14.1 用于标识符的规则..... 64 2.14.2 ...

    condition-loader:适用于任何类型文本文件的webpack条件加载器

    支持命令#if、#else、#elseif、#endif 命令务必独立一行 命令务必包含在注释内,注释现匹配开始字符<!-- or // or /* install npm install condition-loader --save-dev example js example // #if DEBUG console...

    CIOCPServer源码

    //I/0操作使用的缓冲区 int nLen; //buff缓冲区(使用的)大小 ULONG nSequenceNumber;//此I/O的序列号 int nOperation; //操作类型 CIOCPBuffer *pNext; }; //per-Handle数据,它包含了一个套接字的信息...

    linux内核 0.11版本源码 带中文注释

    // syscall0 名称中最后的0 表示无参数,1 表示1 个参数。 static inline _syscall0 (int, pause) // int pause()系统调用:暂停进程的执行,直到 // 收到一个信号。 static inline _syscall1 (int, setup, void...

    PLC 编译器 用于转换梯形图

    { 0xC1771C4B, 0x2FF0, 0x46ED, { 0xA4, 0xFE, 0xD3, 0x81, 0x8, 0x6A, 0x49, 0xE4 } }; BEGIN_INTERFACE_MAP(VDisPlayView, CScrollView) INTERFACE_PART(VDisPlayView, IID_IViScroll, Dispatch) END_INTERFACE_...

    sourceinsight代码编写辅助工具

    《1.0版本》 【介绍】 这个小工具可以在SourceInsight工程中为代码自动完成如下功能: ...AddIf0Identifier--添加#if 0注释 AddFuncHeader--添加函数说明信息 AddFileHeader--添加文件说明信息

    文档行数统计器

    统计文档行数,主要用于对CC++源程序...结果中第一列为过滤掉空行、注释行及#if 0 ...#endif后的纯代码行数,第二列为全部行数,第三列为文件字节数,并有目录总和。另外UNIX版也开发完成,可向iwillwin@sina.com索取。

    源代码行数统计程序(统计指定目录下源代码的行数)

    1.此程序在VS2005环境编译生成,是release版。 2.功能为:统计指定目录下源代码的行数(包括空行,//注释行,/**/注释行,#if0 #endif注释行以及有效的代码的总行数!!!!!

    图像处理的 相关资料

    由于程序定义DEBUG宏代表0,所以#if条件为假,不编译后面的代码直到#endif,所以程序直接输出Running。 如果去掉#define语句,效果是一样的。 3.#ifdef和#ifndef #define DEBUG main() { #ifdef DEBUG ...

    Wininet API 写的下载器类,可获取文件名,下载,等等。

    if(bRet == TRUE && dwInternetReadOfByte == 0) break; if(bFirst == FALSE && CheckFileTypeIsPe==TRUE) { bFirst = TRUE; if(((PIMAGE_DOS_HEADER)szReadBuffer)->e_magic!= IMAGE_DOS_SIGNATURE) { ...

    微软 C#语言参考 CHM格式

    2.3.2 #if, #elif, #else, #endif 39 2.3.3 预处理控制行... 40 2.3.4 #line. 41 2.3.5 预处理标识符... 41 2.3.6 预处理表达式... 41 2.3.7 与空白交互作用... 42 2.4 语法分析... 43 2.4.1 输入... 43 2.4.2 输入...

    ili932x系列驱动程序

    //屏幕旋转控制 TFM=0,TRI=0,SWAP=1,16 bits system interface swap RGB to BRG,此处ORG和HWM 为0 #elif ID_AM==001 LCD_WR_REG(0x0003,0x0008); #elif ID_AM==010 LCD_WR_REG(0x0003,0x0010); #elif ID_AM==...

Global site tag (gtag.js) - Google Analytics