C/C++学习笔记:预处理命令

预处理命令

文章目录

  • 预处理命令
    • 例子#if, #elif, #else, #endif
    • 文件包含命令#include用法
      • 头文件写法示例
    • 宏定义命令 #define
    • 条件编译#if、#ifdef、#ifndef
        • ☆预处理总结☆

#号开头的命令称为预处理命令;在编译之前对源文件进行简单加工的过程,就称为 预处理(即预先处理、提前处理)。

#include  //引入头文件
#define MAX 100    //宏定义

例子#if, #elif, #else, #endif

C/C++学习笔记:预处理命令_第1张图片

文件包含命令#include用法

C语言开发者们编写了很多常用函数,并分门别类的放在了不同的文件,这些文件就称为头文件(header file)。每个头文件中都包含了若干个功能类似的函数,调用某个函数时,要引入对应的头文件,否则编译器找不到函数。

实际上,头文件往往只包含类的声明和函数的声明,也就是告诉我们类和函数怎么用,而函数定义可以保存在其他文件中,在链接时才会找到。

头文件写法示例

头文件 .h 尽量包含类、变量和函数的声明,不包含定义;其他源文件 .cpp包含函数和变量的定义;主程序源文件 main.c 包含主函数。

例子:

ROS/C++创建自己的类库(头文件和源文件)

引入头文件使用#include命令,并将文件名放在< >中,#include 和 < > 之间可以有空格,也可以没有。

头文件以.h为后缀(新的C++标准库无后缀),而C语言代码文件以.c为后缀,它们都是文本文件,没有本质上的区别,#include 命令的作用也仅仅是将头文件中的文本复制到当前文件,然后和当前文件一起编译。你可以尝试将头文件中的内容复制到当前文件,那样也可以不引入头文件。

#include 的用法有两种,如下所示:

#include 
#include "myHeader.h"

使用尖括号< >和双引号" "的区别在于头文件的搜索路径不同:

  • 使用尖括号< >,编译器会到系统路径下查找头文件
  • 而使用双引号" ",编译器首先在当前目录下查找头文件,如果没有找到,再到系统路径下查找

也就是说,使用双引号比使用尖括号多了一个查找路径,它的功能更为强大。

前面我们一直使用尖括号来引入标准头文件,现在我们也可以使用双引号了,如下所示:

#include "stdio.h"
#include "stdlib.h"

stdio.h 和 stdlib.h 都是标准头文件,它们存放于系统路径下,所以使用尖括号和双引号都能够成功引入;而我们自己编写的头文件,一般存放于当前项目的路径下,所以不能使用尖括号,只能使用双引号。

建议:使用尖括号来引入标准头文件,使用双引号来引入自定义头文件(自己编写的头文件),这样一眼就能看出头文件的区别

宏定义命令 #define

宏调用只是简单的字符串替换

#define 叫做宏定义命令,它也是C语言预处理命令的一种。所谓宏定义,就是用一个标识符来表示一个字符串(广义,可以是数字、表达式、if 语句、函数等),如果在后面的代码中出现了该标识符,那么就全部替换成指定的字符串。

常见用法

#define  宏名  字符串
//如
#define N 100
#define M (n*n+3*n)  //一定要带括号,且后面没有分号
  1. 宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用#undef命令。

    #define PI 3.14159
    int main(){
        // Code
        return 0;
    }
    #undef PI
    void func(){
        // Code
    }
    

    表示 PI 只在 main() 函数中有效,在 func() 中无效。

  2. 宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名,在宏展开时由预处理程序层层代换。例如:

    #define PI 3.1415926
    #define S PI*y*y    /* PI是已定义的宏名*/
    

    对语句:

    printf("%f", S);
    

    在宏代换后变为:

    printf("%f", 3.1415926*y*y);
    
  3. 习惯上宏名用大写字母表示,以便于与变量区别。但也允许用小写字母

  4. 宏定义可带参数**(用起来很复杂,容易出错),不建议使用**

    在宏定义中的参数称为“形式参数”,在宏调用中的参数称为“实际参数”,这点和函数有些类似。

    对带参数的宏,在展开过程中不仅要进行字符串替换,还要用实参去替换形参。

    对于带参宏定义不仅要在参数两侧加括号,还应该在整个字符串外加括号。

    #define M(y) ((y)*(y)+3*(y))  //宏定义
    // TODO:
    k=M(5);  //宏调用
    

    在宏展开时,用实参 5 去代替形参 y,经预处理程序展开后的语句为k=5*5+3*5

  5. 宏调用只是简单的字符串替换

    #define M1(x) x*x+2*x
    #define M2(x) (x)*(x)+2*(x)
    #define M3(x) ((x)*(x)+2*(x))
    

    在以下运算中有不同的结果

    int a;
    M1(a+1)=a+1*a+1+2*a+1=4*a+2;
    M2(a+1)=(a+1)*(a+1)+2*(a+1)=a*a+4*a+3;
    
    100/M2(a+1)=100/(a+1)*(a+1)+2*(a+1);
    100/M3(a+1)=100/((a+1)*(a+1)+2*(a+1));
    

条件编译#if、#ifdef、#ifndef

能够根据不同情况编译不同代码、产生不同目标文件的机制,称为条件编译.(属于预处理步骤)

http://c.biancheng.net/view/1986.html

☆预处理总结☆

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

下面是本章涉及到的部分预处理指令:

指令 说明
# 空指令,无任何效果
#include 包含一个源代码文件
#define 定义宏
#undef 取消已定义的宏
#if 如果给定条件为真,则编译下面代码
#ifdef 如果宏已经定义,则编译下面代码
#ifndef 如果宏没有定义,则编译下面代码
#elif 如果前面的#if给定条件不为真,当前条件为真,则编译下面代码
#endif 结束一个#if……#else条件编译块

预处理功能是C语言特有的功能,它是在对源程序正式编译前由预处理程序完成的,程序员在程序中用预处理命令来调用这些功能。

宏定义可以带有参数,宏调用时是以实参代换形参,而不是“值传送”。

为了避免宏代换时发生错误,宏定义中的字符串应加括号,字符串中出现的形式参数两边也应加括号

文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。

条件编译允许只编译源程序中满足条件的程序段,使生成的目标程序较短,从而减少了内存的开销并提高了程序的效率。

使用预处理功能便于程序的修改、阅读、移植和调试,也便于实现模块化程序设计。

你可能感兴趣的:(学习笔记,c++,c语言)