C语言相关知识——预处理

C语言相关知识------预处理

1.C语言编译步骤

  • 预处理
  • 编译
  • 汇编
  • 链接

2.什么是预处理

预处理就是源文件(如.c文件)编译之前,所进行的一部分预备操作,这部分操作有预处理程序来说时自动完成:当源文件在编译时,编译器会调用预处理程序来完成对预处理指令的解析,预处理指令解析完成才能进入下一步的编译过程。

​ 我们为了能够方便看到这个编译细节,我们可以使用下面的命令:

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

3.预处理的功能

1.宏定义

  • 不带参数的宏定义

    语法:

    c 复制代码
    #define 宏名 常量数据

    预处理:此时的预处理只做数据替换,不做类型检查

    注意:我们定义的宏不会占用内存空间,还没有到编译环节,就已经替换成了我们宏中的常量数据。

    宏展开:在预编译时将宏名替换成字符串的的过程称为"宏展开"

    案例:

    c 复制代码
    #include <stdio.h>
    #define PI 3.1415926
    void main()
    {
    	float l,s,r,v;
    	printf("input radius:");
    	scanf("%f",&r);
    	l=2.0*PI*r;
    	s=PI*r*r;
    	v=4.0/3*PI*r*r*r;
    	printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n",l,s,v);
    }
  • 带参数的宏定义

    • 语法:
    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);// 27 9
      	return 0;
      }
  • 宏定义的作用域

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

    • 可以用 #undef 命令终止宏定义的作用域

    • 案例

      c 复制代码
      /**
      * 宏定义的作用域
      */
      #define PI 3.14
      #define DAY 20
      void fun()
      {
      	float r = 4;
      	float s = PI * r * r;
      	int day = DAY;
      }
      #undef PI // 结束PI的作用范围
      #define PI 3.1415926
      void fun1()
      {
      	float r1 = 4;
      	float s1 = PI * r1 * r1;
      	int day = DAY;
      }
      void main()
      {
      fun();
      fun1();
      }
  • 在宏定义中引用一定义的宏名

    • 案例

      c 复制代码
      #include <stdio.h>
      #define R 3.0
      #define PI 3.1415926
      #define L 2*PI*R
      #define S PI*R*R
      void main()
      {
      	printf("L=%f\nS=%f\n",L,S);
      }

2.文件包含

概念

​ 所谓"文件包含"处理是指一个源文件可以将另外一个源文件的全部内容包含进来。这个适用于多文件开发。

预处理

此时的预处理,是将文件中

包含方式

  • 第一种:#include <xxxxxx.h>

​ 系统会到标准库头文件目录下(Linux下 /user/include)查找包含的文件

  • 第二种:#include "xxxxxx.h"

​ 在当前的工程路径下查找,如果未找到,仍然会到标准库头文件目录查找

案例:

algorithm.h

c 复制代码
/**
* 自定义头文件,专门用于存放被外部访问的函数的声明
*/
// 数组的累加和计算
extern int sum(const int *p,int len);

algorithm.c

c 复制代码
/**
* 实现数组元素的累加计算
*/
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 "algorithm.h"
// 如果有n多个外部函数,难道都要一个个的使用extern进行声明?
// 引入外部函数声明
// extern int sum(const int*,int);
int main()
{
	int arr[5] = {12,33,14,55,34};
	int res = sum(arr,5);
	printf("数组累和结果是:%d\n",res);
	return 0;
}

编辑命令:

c 复制代码
gcc algorithm.c app.c -o app // 又包含关系的c文件要一起编译

3.条件编译

概念

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

预处理

将满足条件的语句进行保留,不满足条件的语句进行删除,交给下一步编译

语法

语法一:

c 复制代码
#ifdef 标识 -- 判断标识符定义与否
	..
#else
	..
#endif

语法二:

c 复制代码
#ifndef 标识 -- 判断标识符定义与否
	..
#else
	..
#endif

语法三:

c 复制代码
#if 表达式 -- 根据表达式返回的结果:0-不成立,1-成立
	..
#else
	..
#endif

案例:

c 复制代码
/**
* 预处理-条件编译
*/
#define MINUS 1
int main(void)
{
	#ifndef MINUS // 判断标准是:标识有没有被定义
		int a = 7 - 4;
	#else
		int a = 7 * 4;
	#endif
   
	printf("计算结果:%d\n",a);
	return 0;
}   
c 复制代码
/**
* 预处理-条件编译:输入一行字母字符,根据需要设置条件编译,使之能将字母全改为大写输出,或全改为小写字母输
出。
*/
#include <stdio.h>
// 定义一个标识
#define LETTER 0
void main()
{
	// 测试用的字母字符数组
	char str[20] = "C Language";
    char c;
    int i;
    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");
}

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

语法:

c 复制代码
#ifndef __XXXX_H
#define __XXXX_H
	...
#endif

案例:

algorithm.h

c 复制代码
/**
* 自定义头文件,专门用于存放被外部访问的函数的声明
*/
#ifndef __ALGORITHM_H
#define __ALGORITHM_H
// 数组的累加和计算
extern int sum(const int *p,int len);

#endif
相关推荐
史努比.2 分钟前
Pod控制器
java·开发语言
敲敲敲-敲代码10 分钟前
游戏设计:推箱子【easyx图形界面/c语言】
c语言·开发语言·游戏
ROC_bird..19 分钟前
STL - vector的使用和模拟实现
开发语言·c++
MavenTalk25 分钟前
Move开发语言在区块链的开发与应用
开发语言·python·rust·区块链·solidity·move
simple_ssn32 分钟前
【C语言刷力扣】1502.判断能否形成等差数列
c语言·算法·leetcode
ahadee1 小时前
蓝桥杯每日真题 - 第10天
c语言·vscode·算法·蓝桥杯
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】生产消费模型 & 阻塞队列
java·开发语言·java-ee
2401_840192271 小时前
python基础大杂烩
linux·开发语言·python
@东辰1 小时前
【golang-技巧】- 定时任务 - cron
开发语言·golang·cron
机器人天才一号1 小时前
C#从入门到放弃
开发语言·c#