前面各章中,已经多次使用过#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有两种使用方式:
#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; }
结果
Enter a number: 12
Square root of 12.00 = 3.46