C语言预处理

预处理

C语言的编译步骤

  1. 预处理
  2. 编译
  3. 汇编
  4. 链接

C语言的预处理

预处理就是在源文件编译之前,所进行的一部分预备操作,这部分操作是由预处理程序自动完成;当源文件在编译时,编译器会自动调用预处理程序来完成预处理操作执行的解析,预处理执行解析完成才能进入下一步的编译过程。

c 复制代码
gcc 源文件 -E -o 程序名.[后缀]

预处理功能

宏定义
  • 不带参数的宏定义

    • 语法

      c 复制代码
      #define 宏名 常量数据
    • 宏定义的预处理机制:此时的预处理只做数据替换,不做类型检查

    • 注意:定义的宏不会占用内存空间,还未进入编译环节->运行。我们在编译前已经将宏名替换成了常量数据

    • 宏展开:在预编译时将宏名替换成字符串的过程称为"宏展开"。这里的常量数据是一个不带双引号的字符串

      案例

      c 复制代码
      #include <stdio.h>
      #define PI 3.1415926
      
      int main()
      {
          float l,s,r,v;
          printf("请输入圆的半径:\n");
          scanf("%f",&r);
          
          //计算周长
          l = 2 * PI * r;
          //计算面积
          s = PI * r * r;
          
          printf("l=%10.4f\ns=%10.4f",l,s);
          return 0;
      }
  • 带参数的宏定义

    • 语法:

      c 复制代码
      #define 宏名(参数列表) 参数表达式
    • 面试题

    c 复制代码
    #define multi(a,b) a * b
    • 实现
    c 复制代码
    # include <stdio.h>
    #define multi(a,b) a * b
    
    int main()
    {
        int result = multi(7+2,3);
        printf("%d\n",result);//13
    	return 0;
    }
  • 宏定义的作用域

    • #define命令出现在程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束。#define写在文件开头,函数之前,作为文件一部分,在此文件范围内有效。
    • 可以有#undef命令终止宏定义

    案例

    c 复制代码
    # include <stdio.h>
    #define PI 3.14
    #define DAY 20
    
    void fun()
    {
        float r = 4;
        float s = PI * r * r;
        int day = DAY;
    }
    #undef PI//终止PI范围
    void fun1()
    {
        float r = 4;
        float s = PI * r * r;
        int day = DAY;
    }
    
    int main()
    {
        fun();
        fun1();  
        return 0;
    }
  • 在宏定义中引用已定义的宏名

    • 案例
    c 复制代码
    #include <stdio.h>
    #define R 3.0
    #define PI 3.14
    #define L 2*PI*R
    #dedine S PI*R*R
    
    int main()
    {
        printf("%f,%f",L,S);
        return 0;
    }

文件包含

概念

所谓的文件包含处理是指一个源文件可以将另一个源文件的全部包含进来。这个适用于多文件开发。通常,一个常规的C语言程序会包含多个源码文件(*.c),当某些公共资源需要再各个源码文件中使用,为了避免多次编写相同的代码,我们会进行代码抽取(*.c),并提供公共的访问文件(*.h),然后再各个源码文件中直接包含即可。

*.h中的函数申明必须要在*.c中有对应的函数定义(函数的实现),否则没有意义。

头文件(.h)的内容
  • 头文件中所存放的内容,就是各个源码文件的彼此可见的公共资源。
    1. 全局变量的声明
    2. 普通函数的声明
    3. 静态函数的定义
    4. 宏定义
    5. 结构体、联合体的定义
    6. 枚举常量列表的定义
    7. 其他头文件
  • 实例
c 复制代码
//head.h

extern int global;//全局变量
extern void f1();//普通函数的声明
static void f2();//静态函数定义
{
    ...;
}
#define max(a,b) ((a)>(b)?(a):(b))//宏定义
struct Mod	//结构体定义
{
    ...;
};

union Ater	//联合体定义
{
    ...;
};

#include <stdio.h>//其他头文件-系统库文件
#include "mylib.h"//其他头文件-自定义文件
  • 特别说明:

    1. 全局变量、普通函数的定义一般出现在某个源文件(*.c*.cpp)中,其他源文件想要使用都需要进行声明,因此放在头文件更方便
    2. 静态函数、宏定义、结构体、联合体的定义都只能在其所在的文件可见因此多个源文件需要,放到头文件中定义更为方便、安全
  • 文件包含预处理机制

    此时的预处理,是将文件中的内容替换,文件包含指令

包含方式
  1. #include <xxx.h>

    系统会到标准文件目录(liunx下/user/include)查找包含文件

  2. #include "xxx.h"

    在工程路径下查找,若未找到仍然去标准库文件目录查找

案例

myhead.h

c 复制代码
#ifndef _MYHEAD_H
#define _MYHEAD_H
// 数组的累加和计算
extern int sum(const int *, int);
// extern int sum(const int *p,int len);
#endif //_MYHEAD_H

myhead.c

c 复制代码
#include "myhead.h"
int sum(const int *p, int len)
{
    int sum = 0;
    register int i = 0;
    for (; i < len; i++)
    {
        sum += *(p + i);
    }
    return sum;
}

app.c

c 复制代码
#include <stdio.h>
#include "myhead.h"
int main(int argc, char *argv[])
{
    int arr[5] = {12, 13, 14, 15, 16};
    int res = sum(arr, 5);
    printf("数组累加和的结果是:%d\n", res);
    return 0;
}

多文件编译命令

c 复制代码
gcc app.c myhead.c -o app
条件编译

概念:根据设定的条件选择待选择编译的语句代码。

条件编译预处理机制:将满足条件的语句进行保留,不满足条件的语句进行删除,交给下一步编译

语法

  1. 语法一

    c 复制代码
    #ifdef 标识	//判断标识符是否定义(定义为真,未定义为假)
    ..
    #else
    ..
    #endif
  2. 语法二

    c 复制代码
    #ifndef 标识	//判断标识符是否定义(未定义为真,定义为假)
    ..
    #else
    ..
    #endif
  3. 语法三

    c 复制代码
    #if  表达式  //判断表达式的结果(成立为真,不成立为假)
    ..
    #else
    ..
    #endif    

    案例

    c 复制代码
    #include <stdio.h>
    #define LETTER 0
    int main(int argc, char *argv[])
    {
        // 测试用的字母字符
        char str[20] = "C Language";
        char c;
        int i = 0;
        while ((c = str[i]) != '\0')
        {
            i++;
    #if LETTER
            if (c >= 'a' && c <= 'z')
            {
                c -= 32;
            }
    #else
            if (c >= 'A' && c <= 'Z')
            {
                c += 32;
            }
    #endif
            printf("%c", c);
        }
        printf("\n");
        return 0;
    }

避免头文件重复包含的方法

由于头文件包含指令#include的本质是复制粘贴,并且一个头文件可以嵌套包含其他头文件,因为很容易出现:头文件重复包含

语法:

c 复制代码
#ifndef __XXXX_H //一般取头文件名称的大写
#define __XXXX_H
...
#endif
相关推荐
zeijiershuai4 分钟前
Java jdk8新特性:Stream 流
java·开发语言
YOULANSHENGMENG4 分钟前
linux上使用cmake编译的方法
开发语言·c++
学计算机的睿智大学生17 分钟前
关于python的数据分析与应用
开发语言·python·数据分析
晚安~~20 分钟前
共享充电宝系统|Java|SSM|VUE| 前后端分离
java·开发语言·tomcat·maven
找了一圈尾巴31 分钟前
Wend看源码-Java-Arrays 工具集学习
java·开发语言·学习
HelloZheQ32 分钟前
Java与AI:构建智能应用的强大组合
java·开发语言·人工智能
自律小仔32 分钟前
前端开发语言涉及到 的基本数据类型(Primitive Data Types)
开发语言·后端·golang
S-X-S35 分钟前
八万字Java面试高频题目汇总(冲刺春招!)
java·开发语言·面试
Chenglin_Yu36 分钟前
Python嵌套列表的浅拷贝与深拷贝
开发语言·python
码农丁丁1 小时前
[python3]Excel解析库-xlutils
开发语言·python·excel