搜索
bottom↓
回复: 53

学单片机基础c语言之条件编译——每个程序员都必须知道的

  [复制链接]

出0入0汤圆

发表于 2011-8-3 09:49:13 | 显示全部楼层 |阅读模式
C语言的条件编译#if, #elif, #else, #endif、#ifdef, #ifndef
有些程序在调试、兼容性、平台移植等情况下可能想要通过简单地设置一些参数就生成一个不同的软件,这当然可以通过变量设置,把所有可能用到的代码都写进去,在初始化时配置,但在不同的情况下可能只用到一部分代码,就没必要把所有的代码都写进去,就可以用条件编译,通过预编译指令设置编译条件,在不同的需要时编译不同的代码。
   (一)条件编译方法
   条件编译是通过预编译指令来实现的,主要方法有:
   1、#if, #elif, #else, #endif
#if 条件 1
 代码段 1
#elif 条件 2
   代码段 2
...
#elif 条件 n
 代码段 n
#else
 代码段 n+1
#endif
  即可以设置不同的条件,在编译时编译不同的代码,预编译指令中的表达式与C语言本身的表达式基本一至如逻辑运算、算术运算、位运算等均可以在预编译指令中使用。之所以能够实现条件编译是因为预编译指令是在编译之前进行处理的,通过预编译进行宏替换、条件选择代码段,然后生成最后的待编译代码,最后进行编译。
   #if的一般含义是,如果#if后面的常量表达式为true,则编译它所控制的代码,如条件1成立时就代码段1,条件1不成立再看条件2是否成立,如果条件2成立则编译代码段2,否则再依次类推判断其它条件,如果条件1-N都不成力则会编译最后的代码段n+1.
   2、#ifdef, #else, #endif或#ifndef, #else, #endif
  条件编译的另一种方法是用#ifdef与#ifndef命令,它们分别表示“如果有定义”及“如果无定义”。有定义是指在编译此段代码时是否有某个宏通过 #define 指令定义的宏,#ifndef指令指找不到通过#define定义的某宏,该宏可以是在当前文件此条指令的关面定义的,也可以是在其它文件中,但在此指令之前包含到该文件中的。
#ifdef的一般形式是:
 #ifdef macro_name
    代码段 1
#else
    代码段 2
#endif


#ifdef的一般形式是:

#ifndef macro_name
    代码段 2
#else
    代码段 1
#endif
   这两段代码的效果是完全一样的。
   3、通过宏函数defined(macro_name)
  参数为宏名(无需加""),如果该macro_name定义过则返回真,否则返回假,用该函数则可以写比较复杂的条件编译指令如
 #if defined(macro1) || (!defined(macro2) && defined(macro3))
...
#else
...
#endif
   (二)条件编译技巧与示例
   (1)#ifdef和#defined()比较
  首先比较一下这两种方法,第一种方法只能判断一个宏,如果条件比较复杂实现起来比较烦锁,用后者就比较方便。如有两个宏MACRO_1,MACRO_2只有两个宏都定义过才会编译代码段A,分别实现如下:
 #ifdef MACRO_1
#ifdef MACRO_2
    代码段 A
#endif
#endif

或者
#if defined(MACRO_1) && defined(MACRO_2)
#endif
  同样,要实现更复杂的条件用#ifdef更麻烦,所以推荐使用后者,因为即使当前代码用的是简单的条件编译,以后在维护、升级时可能会增加,用后者可维护性较强。旧的编译器可能没有实现#defined()指令,C99已经加为标准。要兼容老的编译器,还需用#ifdef指令。
   2、#if与 #ifdef或#if defined()比较
   比如自己写了一个printf函数,想通过一个宏MY_PRINTF_EN实现条件编译,用#if可实现如下
C语言的条件编译。
 #define MY_PRINTF_EN 1

#if MYS_PRINTF_EN == 1
 int printf(char* fmt, char* args, ...)
{
    ...
}
#endif
  如果宏MY_PRINTF_EN定义为1则编译这段代码,如果宏定义不为1或者没有定义该宏,则不编译这段代码。同样也可以通过#ifdef或者#defined()实现,如
 #define MY_PRINTF_EN 1

#if defined(MY_PRINTF_EN)
 int printf(char* fmt, char* args, ...)
{
    ...
}
#endif
  在这种情况下两种方法具有异曲同工之妙,但试想如果你为了节约代码写了两个printf函数,在不同情况下使用不同的printf函数,一个是精简版一个是全功能标准版,如:
 #define MY_PRINTF_SIMPLE

#ifdef MY_PRINTF_SIMPLE
   void printf(*str) // 向终端简单地输出一个字符串
{...
}
#endif
#ifdef MY_PRINTF_STANDARD
 int printf(char* fmt, char* args, ...)
{...
}
#endif

同样可以用#if defined()实现
#define MY_PRINTF_SIMPLE

#if defined(MY_PRINTF_SIMPLE)
   void printf(*str) // 向终端简单地输出一个字符串
{
    ...
}
#elif defined(MY_PRINTF_STANDARD)
 int printf(char* fmt, char* args, ...)
{
    ...
}
#endif
  两种方法都可以实现,但可见后者更方便。但试想如果你有三个版本,用前者就更麻烦了,但方法相似,用后者就更方便,但仍需三个宏进行控制,你要住三个宏,改进一下就用#if可以用一个宏直接控制N种情况如:
 #define MY_PRINTF_VERSION     1

#if MY_PRINTF_VERSION == 1
   void printf(*str) // 向终端简单地输出一个字符串
{
    ...
}
#elif MY_PRINTF_VERSION == 2
 int printf(char* fmt, char* args, ...)
{
    ...
}
#elif MY_PRINTF_VERSION == 3
int printf(unsigned char com_number, char* str)
{
    ...
}
#else
    默认版本
#endif
   这样,你只需修改一下数字就可以完成版本的选择了
   看来好像用#if 比较好了,试想如下情况:你写了一个配置文件叫做config.h用来配置一些宏,通过这些宏来控制代码,如你在config.h的宏
   #define MY_PRINTF_EN 1
   来控制是否需要编译自己的printf函数,而在你的源代码文件printf.c中有如下指令
 #i nclude "config.h"
#if MY_PRINTF_EN == 1
 int printf(char* fmt, char* args, ...)
{
    ...
}
#endif
  但这样也会有一个问题,就是如果你忘了在config.h中添加宏MY_PRINTF_EN,那么自己写的printf函数也不会被编译,有些编译器会给出警告:MY_PRINTF_EN未定义。如果你有两个版本的想有一个默认版本,可以在printf.c中这样实现
 #incldue "config.h"
#if !defined(MY_PRINTF_VERSION)
  #define MY_PRINTF_VERSION   1
#endif

#if MY_PRINTF_VERSION == 1
   void printf(*str) // 向终端简单地输出一个字符串
{
    ...
}
#elif MY_PRINTF_VERSION == 2
 int printf(char* fmt, char* args, ...)
{
    ...
}
#elif MY_PRINTF_VERSION == 3
int printf(unsigned char com_number, char* str)
{
    ...
}
#endif
这种情况下还得用到#ifdef或#if defined(),你可以不用动主体的任何代码,只需要修改printf.c文件中MY_RPINTF_VERSION宏的数字就可以改变了,如果用前面那种方法还得拖动代码,在拖动中就有可能造成错误。
   再试想,如果软件升级了,或者有了大的改动,原来有三个版本,现在只剩下两个版本了,如
 #if MY_PRINTF_VERSION == 2
 int printf(char* fmt, char* args, ...)
{
    ...
}
#elif MY_PRINTF_VERSION == 3
int printf(unsigned char com_number, char* str)
{
    ...
}
#endif
  因为这些核心代码不想让使用这些代码的人关心,他们只需要修改config.h文件,那就要在printf.c中实现兼容性。如果以前有人在config.h配置宏MY_PRINTF_VERSION为1,即有
   #define MY_PRINTF_VERSION   1
   而现在没有1版本了,要想兼容怎么办?那当然可以用更复杂的条件实现如:
 #if MY_PRINTF_VERSION == 2 || MY_PRINTF_VERSION == 1
 int printf(char* fmt, char* args, ...)
{
    ...
}
#elif MY_PRINTF_VERSION == 3
int printf(unsigned char com_number, char* str)
{
    ...
}
#endif
   不过还有另外一种方法,即使用#undef命令
 #if MY_PRINTF_VERSION == 1
  #undef MY_PRINTF_VERSION
  #define MY_PRINTF_VERSION  2
#endif
#if MY_PRINTF_VERSION == 2
 int printf(char* fmt, char* args, ...)
{
    ...
}
#elif MY_PRINTF_VERSION == 3
int printf(unsigned char com_number, char* str)
{
    ...
}
#endif

   用#if还有一个好处,如果你把宏名记错了,把MY_PRINTF_EN定义成了MY_PRINT_EN,那么你用#ifdef MY_PRINTF_EN或者#if defined(MY_PRINTF_EN)控制的代码就不能被编译,查起来又不好查,用#if MY_PRINTF_EN ==1控制就很好查,因为你把MY_PRINTF_EN定义成MY_PRINT_EN,则MY_PRINTF_EN实际上没有定义,那么编译器会给出警告#if MY_PRINTF_EN == 1中的MY_PRINTF_EN没有定义,但错就比较快。

出0入0汤圆

 楼主| 发表于 2011-8-3 18:43:34 | 显示全部楼层
哈哈哈哈

出0入0汤圆

发表于 2012-6-19 10:45:07 | 显示全部楼层
写得很详细。

出0入0汤圆

发表于 2012-6-19 11:20:29 | 显示全部楼层
总结的很好

出0入0汤圆

发表于 2012-6-27 11:59:12 | 显示全部楼层

出0入0汤圆

发表于 2012-6-27 13:12:53 | 显示全部楼层
非常的不错,顶一个!

出50入0汤圆

发表于 2012-6-27 13:58:07 | 显示全部楼层
做大型程序,移植时很有用。顶起

出0入0汤圆

发表于 2012-6-27 17:18:47 | 显示全部楼层
条件编译 要学

出0入0汤圆

发表于 2012-6-27 17:29:20 | 显示全部楼层
正在学习C ING

出0入0汤圆

发表于 2012-6-27 18:14:25 | 显示全部楼层
存档一下!!!

出0入0汤圆

发表于 2014-1-11 08:31:20 | 显示全部楼层
写得不错,学习

出0入0汤圆

发表于 2014-1-13 11:40:00 | 显示全部楼层
写得挺好!很深入

出0入0汤圆

发表于 2014-1-13 11:53:42 | 显示全部楼层
顶一下!确实不错,以后改程序就方便了。

出0入0汤圆

发表于 2014-1-13 11:56:07 | 显示全部楼层
没想到这个被加精的帖子看得人竟然那么少,再顶下.......

出0入0汤圆

发表于 2014-1-13 11:57:25 | 显示全部楼层
写得好 顶起

出0入13汤圆

发表于 2014-2-23 19:18:30 | 显示全部楼层
写得很好,要认真学习

出0入0汤圆

发表于 2014-2-23 22:13:31 | 显示全部楼层

出0入0汤圆

发表于 2014-2-24 08:29:42 | 显示全部楼层
标记一下   谢谢分享

出0入0汤圆

发表于 2014-2-24 21:51:22 | 显示全部楼层
标记,留恋,存档

出0入0汤圆

发表于 2014-2-25 09:33:54 | 显示全部楼层
mark                  

出0入0汤圆

发表于 2014-2-25 09:37:30 | 显示全部楼层
111111111111111111111                 

出0入0汤圆

发表于 2014-2-25 11:12:15 | 显示全部楼层
           mark

出0入0汤圆

发表于 2014-2-25 13:13:19 | 显示全部楼层
mark
            

出0入0汤圆

发表于 2014-2-25 23:45:09 来自手机 | 显示全部楼层
marK            

出0入0汤圆

发表于 2014-2-25 23:49:46 | 显示全部楼层
学习!!!!!!!

出0入0汤圆

发表于 2014-5-5 13:44:12 | 显示全部楼层
好东西啊,学习了

出0入0汤圆

发表于 2014-5-5 14:05:59 | 显示全部楼层
写得很详细

出0入0汤圆

发表于 2014-5-5 14:40:59 | 显示全部楼层
这不是C和指针上的吗

出0入0汤圆

发表于 2014-5-7 20:22:49 | 显示全部楼层

好东西啊,学习了

出0入0汤圆

发表于 2014-5-7 20:56:28 | 显示全部楼层
不错,支持分享

出0入0汤圆

发表于 2014-5-7 21:36:10 | 显示全部楼层
现在没那么高深先收藏了。还看不懂。。

出0入0汤圆

发表于 2014-5-7 21:58:49 | 显示全部楼层
学习                    

出0入0汤圆

发表于 2014-5-8 09:51:35 | 显示全部楼层
正好是我需要

出0入0汤圆

发表于 2014-5-9 11:50:22 | 显示全部楼层
谢谢LZ,很详细。。也很有帮助。

出0入0汤圆

发表于 2014-5-9 12:42:10 | 显示全部楼层
mark........

出0入0汤圆

发表于 2014-5-9 13:45:35 | 显示全部楼层
   mark!!!

出0入0汤圆

发表于 2014-5-9 14:11:29 | 显示全部楼层
学习了。

出0入8汤圆

发表于 2014-5-10 09:39:29 | 显示全部楼层
好好学习天天向上,收藏了学!

出0入0汤圆

发表于 2014-5-10 20:43:03 来自手机 | 显示全部楼层
楼主辛苦,学习了。

出0入0汤圆

发表于 2014-5-10 21:07:46 | 显示全部楼层
好东西收藏了。

出0入0汤圆

发表于 2014-5-10 21:32:30 | 显示全部楼层
呵呵,好东西,前几天还查了一下#elif,硬是想不起怎么写了,怎么写都不对!早看到这个就好了!

出0入0汤圆

发表于 2014-8-6 22:05:35 | 显示全部楼层
谢谢楼主的分享啊!

出0入0汤圆

发表于 2014-8-7 09:05:16 | 显示全部楼层
学习了 非常感谢!!!

出0入0汤圆

发表于 2014-8-7 09:14:05 | 显示全部楼层
收场了,顺道顶一下

出0入0汤圆

发表于 2014-8-7 09:18:02 | 显示全部楼层
好详细
好nice

出0入0汤圆

发表于 2014-8-29 00:53:23 | 显示全部楼层
很好。。。。

出0入0汤圆

发表于 2014-8-29 08:28:30 | 显示全部楼层
谢的很好

出0入8汤圆

发表于 2014-8-29 08:41:40 | 显示全部楼层
好高端的样子~

出0入0汤圆

发表于 2014-8-29 09:14:31 | 显示全部楼层
不错,学习了

出0入0汤圆

发表于 2014-8-29 09:53:22 | 显示全部楼层
总结的很好,顶一个……

出0入0汤圆

发表于 2014-8-29 14:45:15 | 显示全部楼层
顶一个,确实该知道的

出0入0汤圆

发表于 2014-8-31 23:11:55 | 显示全部楼层
总结得非常不错,对于初学者来说有很大的帮助,解决很多困惑!

出0入0汤圆

发表于 2014-9-1 08:12:00 | 显示全部楼层
好好学习天天向上

出0入0汤圆

发表于 2014-9-1 08:43:18 | 显示全部楼层
感觉受益匪浅
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-1 06:50

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表