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