C/C++预处理指令 #define,#ifdef,#ifndef,#endif

转载 2016年08月29日 18:24:57
本文转载自

C/C++预处理指令#define,#ifdef,#ifndef,#endif…

本文主要记录了C/C++预处理指令,常见的预处理指令如下:

  1. #空指令,无任何效果
  2. #include包含一个源代码文件
  3. #define定义宏
  4. #undef取消已定义的宏
  5. #if如果给定条件为真,则编译下面代码
  6. #ifdef如果宏已经定义,则编译下面代码
  7. #ifndef如果宏没有定义,则编译下面代码
  8. #elif如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
  9. #endif结束一个#if……#else条件编译块
  10. #error停止编译并显示错误信息

本来只是想了解一下#ifdef,#ifndef,#endif的,没想到查出来这么多的预处理指令,上面的多数都是常见的,但是平时没有怎么注意预处理这方面的内容,所以这里梳理一下知识吧。同时有什么不妥的地方,或者遗漏了什么内容,还请留言指出。


什么是预处理指令?

预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。

以前没有在意的学者注意了,预处理指令是在编译器进行编译之前进行的操作.预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器。可见预处理过程先于编译器对源代码进行处理。在很多编程语言中,并没有任何内在的机制来完成如下一些功能:在编译时包含其他源文件、定义宏、根据条件决定编译时是否包含某些代码(防止重复包含某些文件)。要完成这些工作,就需要使用预处理程序。尽管在目前绝大多数编译器都包含了预处理程序,但通常认为它们是独立于编译器的。预处理过程读入源代码,检查包含预处理指令的语句和宏定义,并对源代码进行响应的转换。预处理过程还会删除程序中的注释和多余的空白字符。


#include包含一个源代码文件

这个预处理指令,我想是见得最多的一个,简单说一下,第一种方法是用尖括号把头文件括起来。这种格式告诉预处理程序在编译器自带的或外部库的头文件中搜索被包含的头文件。第二种方法是用双引号把头文件括起来。这种格式告诉预处理程序在当前被编译的应用程序的源代码文件中搜索被包含的头文件,如果找不到,再搜索编译器自带的头文件。采用两种不同包含格式的理由在于,编译器是安装在公共子目录下的,而被编译的应用程序是在它们自己的私有子目录下的。一个应用程序既包含编译器提供的公共头文件,也包含自定义的私有头文件。采用两种不同的包含格式使得编译器能够在很多头文件中区别出一组公共的头文件。


#define定义宏

有关#define这个宏定义,在C语言中使用的很多,因为#define存在一些不足,C++强调使用const来定义常量。宏定义了一个代表特定内容的标识符。预处理过程会把源代码中出现的宏标识符替换成宏定义时的值。记住仅仅是进行标识符的替换。下面列举一些#define的使用:

  1. 用#define实现求最大值和最小值的宏
    复制代码
    #include <stdio.h>
    #define MAX(x,y) (((x)>(y))?(x):(y))
    #define MIN(x,y) (((x)<(y))?(x):(y))
    int main(void)
    {
    #ifdef MAX    //判断这个宏是否被定义
        printf("3 and 5 the max is:%d\n",MAX(3,5));
    #endif
    #ifdef MIN
        printf("3 and 5 the min is:%d\n",MIN(3,5));
    #endif
        return 0;
    }
    
    /*
     * (1)三元运算符要比if,else效率高
     * (2)宏的使用一定要细心,需要把参数小心的用括号括起来,
     * 因为宏只是简单的文本替换,不注意,容易引起歧义错误。
    */
    复制代码
  2. 宏定义的错误使用
    复制代码
    #include <stdio.h>
    #define SQR(x) (x*x)
    int main(void)
    {
        int b=3;
    #ifdef SQR//只需要宏名就可以了,不需要参数,有参数的话会警告
        printf("a = %d\n",SQR(b+2));
    #endif
        return 0;
    }
    
    /*
     *首先说明,这个宏的定义是错误的。并没有实现程序中的B+2的平方
     * 预处理的时候,替换成如下的结果:b+2*b+2
     * 正确的宏定义应该是:#define SQR(x) ((x)*(x))
     * 所以,尽量使用小括号,将参数括起来。
    */
    复制代码
  3. 宏参数的连接
    复制代码
    #include <stdio.h>
    #define STR(s) #s
    #define CONS(a,b) (int)(a##e##b)
    int main(void)
    {
    #ifdef STR
        printf(STR(VCK));
    #endif
    #ifdef CONS
        printf("\n%d\n",CONS(2,3));
    #endif
        return 0;
    }
    
    /* (绝大多数是使用不到这些的,使用到的话,查看手册就可以了)
     * 第一个宏,用#把参数转化为一个字符串
     * 第二个宏,用##把2个宏参数粘合在一起,及aeb,2e3也就是2000
    */
    复制代码
  4. 用宏得到一个字的高位或低位的字节
    复制代码
    #include <stdio.h>
    #define WORD_LO(xxx) ((byte)((word)(xxx) & 255))
    #define WORD_HI(xxx) ((byte)((word)(xxx) >> 8))
    int main(void)
    {
        return 0;
    }
    
    /*
     * 一个字2个字节,获得低字节(低8位),与255(0000,0000,1111,1111)按位相与
     * 获得高字节(高8位),右移8位即可。
    */
    复制代码
  5. 用宏定义得到一个数组所含元素的个数
    复制代码
    #include <stdio.h>
    #define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))
    int main(void)
    {
        int array[100];
    #ifdef ARR_SIZE
        printf("array has %d items.\n",ARR_SIZE(array));
    #endif
        return 0;
    }
    /*
     *总的大小除以每个类型的大小
     */
    复制代码

关于#define宏的使用,应该特别小心,尤其是含有参数计算的时候如小2示例,最保险的做法将参数用括号括起来。


#ifdef,#ifndef,#endif...的使用

以下这些预编译指令,都是条件编译指令,也就是说,将决定那些代码被编译,而哪些不被编译。

  1. 示例1:
    复制代码
    #include <stdio.h>
    #include <stdlib.h>
    #define DEBUG
    int main(void)
    {
        int i = 0;
        char c;
        while(1)
        {
            i++;
            c = getchar();
            if('\n' != c)
            {
                getchar();
            }
            if('q' == c || 'Q' == c)
            {
    #ifdef DEBUG//判断DEBUG是否被定义了
                printf("We get:%c,about to exit.\n",c);
    #endif
                break;
            }
            else
            {
                printf("i = %d",i);
    #ifdef DEBUG
                printf(",we get:%c",c);
    #endif
                printf("\n");
            }
        }
        printf("Hello World!\n");
        return 0;
    }
    
    /*#endif用于终止#if预处理指令。*/
    复制代码
  2. #ifdef 和 #ifndef
    复制代码
    #include <stdio.h>
    #define DEBUG
    main()
    {
    #ifdef DEBUG
        printf("yes ");
    #endif
    #ifndef DEBUG
        printf("no ");
    #endif
    }
    //#ifdefined等价于#ifdef;
    //#if!defined等价于#ifndef
    复制代码
  3. #else指令

    001

  4. #elif指令

    002

  5. 其他一些指令
    #error指令将使编译器显示一条错误信息,然后停止编译。
    #line指令可以改变编译器用来指出警告和错误信息的文件号和行号。
    #pragma指令没有正式的定义。编译器可以自定义其用途。典型的用法是禁止或允许某些烦人的警告信息。

小结:

预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作。说白了,就是对源文件进行编译前,先对预处理部分进行处理,然后对处理后的代码进行编译。这样做的好处是,经过处理后的代码,将会变的很精短。

#define #if #ifdef #ifndef 作用和区别

#define #define 用来进行定义 #define kTabBar_Height 49.0f #define kString @"哈哈哈"1212 #if #if ...
  • st646889325
  • st646889325
  • 2016年12月07日 09:11
  • 2050

C++预处理命令

预处理指令可以要求预处理器在程序编译之前,先进行加入其他文件的内容‘文字取代以及选择性编译等工作。 1、预处理器 预处理器是编译器的一部分,当我们将原始程序代码交由编译器编译前,预处理器会按照...
  • sinat_20265495
  • sinat_20265495
  • 2016年04月04日 22:57
  • 412

C语言三种预处理功能

1. 宏定义 2. 文件包含 3. 条件编译 伪指令(或预处理指令)定义: 预处理指令是以#号开头的代码行。#号必须是该行除了任何空白字符外的第一个字符。#后是指令关键字,在关键字和#号之间允许存...
  • u012050154
  • u012050154
  • 2016年06月15日 15:37
  • 6998

C【预处理指令】

014-预处理指令-C语言笔记 学习目标 1.【掌握】枚举 2.【掌握】typedef关键字 3.【理解】预处理指令 4.【掌握】#define宏定义 5.【掌握】条件编译 6.【掌...
  • luolianxi
  • luolianxi
  • 2015年10月16日 01:04
  • 484

C++ 高级篇(五)—— 预处理指令

预处理指令是我们写在程序代码中的给预处理器(preprocessor)的 命令,而不是程序本身的语句。预处理器在我们编译一个C++程序时由编译器自动执行,它负责控制对程序代码的第一次验证和消化。 所有...
  • zqixiao_09
  • zqixiao_09
  • 2016年05月23日 19:11
  • 2356

C++__函数与预处理

在一个程序文件中可以包含若干个函数。无论把一个程序划分为多少个程序模块,但只能有一个main函数。程序总是从main函数开始执行的。在程序运行过程中,由主函数调用其他函数,其他函数也可以互相调用。 ...
  • yf289178199
  • yf289178199
  • 2017年07月01日 15:30
  • 186

#ifndef/#define/#endif使用详解

想必很多人都看过“头文件中的 #ifndef/#define/#endif 防止该头文件被重复引用”。但是是否能理解“被重复引用”是什么意思?是不能在不同的两个文件中使用include来包含这个头文件...
  • abc5382334
  • abc5382334
  • 2014年01月09日 22:22
  • 74270

#ifndef#define#endif 和 ifdef#endif 的用法(整理) 原作者:icwk

#ifndef        头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问...
  • fulva
  • fulva
  • 2012年11月21日 16:10
  • 2851

深入理解C/C++混合编程(关于#ifdef __cplusplus extern "C" {...}的用法)

本篇文章是对C/C++混合编程进行了详细的分析介绍,需要的朋友参考下。         在工作中,C、C++密不可分,做我们嵌入式方面的,当然更多的是C,但,有时候却少不了C++,而且是C、C++混搭...
  • zzwdkxx
  • zzwdkxx
  • 2015年03月13日 18:20
  • 4074

关于C++zhong #ifndef XXX_H #difine XXX_H #endif 那些事

在学习C++的过程中,我们经常发现在头文件前部有一些标识符定义,比如:#ifndef XXX_H  #difine XXX_H  这些是什么呢? #ifndef SeqList_H #defi...
  • CWY_007
  • CWY_007
  • 2017年04月02日 10:30
  • 777
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C/C++预处理指令 #define,#ifdef,#ifndef,#endif
举报原因:
原因补充:

(最多只允许输入30个字)