前面各章中,已经多次使用过#include命令。使用库函数之前,应该用#include引入对应的头文件。这种以#号开头的命令称为预处理命令。
C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。
所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。
下面列出了所有重要的预处理器指令:

C语言代码要经过编译和链接才能生成可执行程序:
编译是针对单个源文件(.c 文件)的,有多少个源文件就生成多少个目标文件,并且在生成过程中不受其他源文件的影响。也就是说,每个源文件都是独立编译的。
链接器的作用就是将这些目标文件拼装成一个可执行程序,并为代码(函数)和数据(变量、字符串等)分配好虚拟地址,这和搭积木的过程有点类似。
编译的原理比较复杂,涉及到大量的算法和正则表达式,我们这门课不涉及C语言的编译。
在实际开发中,有时候在编译之前还需要对源文件进行简单的处理。例如,我们希望自己的程序在 Windows 和 Linux 下都能够运行,那么就要在 Windows 下使用 VS 编译一遍,然后在 Linux 下使用 GCC 编译一遍。
但是现在有个问题,程序中要实现的某个功能在 VS 和 GCC 下使用的函数不同(假设 VS 下使用 a(),GCC 下使用 b()),VS 下的函数在 GCC 下不能编译通过,GCC 下的函数在 VS 下也不能编译通过,怎么办呢?
这就需要在编译之前先对源文件进行处理:如果检测到是 VS,就保留 a() 删除 b();如果检测到是 GCC,就保留 b() 删除 a()。
这些在编译之前对源文件进行简单加工的过程,就称为预处理(即预先处理、提前处理)。
预处理主要是处理以#开头的命令,例如#include <stdio.h>等。预处理命令要放在所有函数之外,而且一般都放在源文件的前面。
预处理是C语言的一个重要功能,由预处理程序完成。当对一个源文件进行编译时,系统将自动调用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。
编译器会将预处理的结果保存到和源文件同名的.i文件中,例如 main.c 的预处理结果在 main.i 中。和.c一样,.i也是文本文件,可以用编辑器打开直接查看内容。
C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等,合理地使用它们会使编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。
#include命令
#include 是文件包含命令,主要用来引入对应的头文件。#include 的处理过程很简单,就是将头文件的内容插入到该命令所在的位置,从而把头文件和当前源文件连接成一个源文件,这与复制粘贴的效果相同。
#include有两种使用方式:
|
1 2 |
#include <stdio.h> #include "myHeader.h" |
使用尖括号< >和双引号” “的区别在于头文件的搜索路径不同,包含标准库的头文件建议用尖括号,包含自定义的头文件建议用双引号。
使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找;使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。
用户编程时可根据自己文件所在的目录来选择某一种命令形式。
说明:
- 一个 #include 命令只能包含一个头文件,多个头文件需要多个 #include 命令;
- 文件包含允许嵌套,也就是说在一个被包含的文件中又可以包含另一个文件。
不同的头文件下包含不同的库函数
不同的头文件下的库函数
| C 头文件 | 描述 |
|---|---|
| <assert.h> | 程序断言函数 |
| <ctype.h> | 字符类型函数 |
| <locale.h> | 本地化功能 |
| <math.h> | 数学函数 |
| <setjmp.h> | 跳转功能函数 |
| <signal.h> | 信号处理函数 |
| <stdarg.h> | 可变参数处理函数 |
| <stdio.h> | 标准输入输出函数 |
| <stdlib.h> | 标准实用功能函数 |
| <string.h> | String handling functions |
| <time.h> | 时间日期函数 |
程序断言函数 – 断言函数,用于在调试过程中捕捉程序的错误。
“断言”在语文中的意思是“断定”、“十分肯定地说”,在编程中是指对某种假设条件进行检测,如果条件成立就不进行任何操作,如果条件不成立就捕捉到这种错误,并打印出错误信息,终止程序执行。
assert() 会对表达式expression进行检测:
- 如果expression的结果为 0(条件不成立),那么断言失败,表明程序出错,assert() 会向标准输出设备(一般是显示器)打印一条错误信息,并调用 abort() 函数终止程序的执行;
- 如果expression的结果为非 0(条件成立),那么断言成功,表明程序正确,assert() 不进行任何操作
在大部分编译器下,assert() 是一个宏;在少数的编译器下,assert() 就是一个函数。我们无需关心这些差异,只管把 assert() 当做函数使用即可。
assert() 的用法很简单,我们只要传入一个表达式,它会计算这个表达式的结果:如果表达式的结果为“假”,assert() 会打印出断言失败的信息,并调用 abort() 函数终止程序的执行;如果表达式的结果为“真”,assert() 就什么也不做,程序继续往后执行。
例1.
#include <stdio.h>
#include <assert.h>
int main(){
int m, n, result;
scanf("%d %d", &m, &n);
assert(n != 0); //写作 assert(n) 更加简洁
result = m / n;
printf("result = %d\n", result);
return 0;
}

Standard Utility Functions (stdlib.h) (选修)
abort– Abnormal termination of a programabs– Integer absolute value (magnitude)assert– Macro for Debugging Diagnosticsatexit– Request execution of functions at program exitatof– String to double or floatatoi– String to integerbsearch– Binary searchcalloc– Allocate space for arraysdiv– Divide two integersecvtbuf– Double or float to string of digitsecvt– Double or float to string of digits (malloc result)__env_lock– Lock environment list for getenv and setenvgvcvt– Format double or float as stringexit– End program executiongetenv– Look up environment variablelabs– Long integer absolute value (magnitude)ldiv– Divide two long integersmalloc– Allocate memoryrealloc– Reallocate memoryfree– Free previously allocated memorymallinfo– Get information about allocated memory__malloc_lock– Lock memory pool for malloc and freembstowcs– Minimal multibyte string to wide string convertermblen– Minimal multibyte lengthmbtowc– Minimal multibyte to wide character converterqsort– Sort an arrayrand– Pseudo-random numbersstrtod– String to double or floatstrtol– String to longstrtoul– String to unsigned longsystem– Execute command stringwcstombs– Minimal wide string to multibyte string converterwctomb– Minimal wide character to multibyte converter
例1.计算一个数的平方根
#include <stdio.h>
#include <math.h>
int main()
{
float num, root;
printf("Enter a number: ");
scanf("%f", &num);
// Computes the square root of num and stores in root.
root = sqrt(num);
printf("Square root of %.2f = %.2f", num, root);
return 0;
}
结果
|
1 2 |
Enter a number: 12 Square root of 12.00 = 3.46 |