第16章 C预处理器和C库
16.1 翻译程序的第一步
预处理之前,编译器对程序进行一些翻译处理。
1,将源代码出现的字符映射到源字符集。
2,将物理行转换成逻辑行
printf(“That's wond\
erful!\n");
转成
printf(“That's wonderful!\n");
3,编译器把文本划分成预处理记号序列、空白序列和注释序列。
编译器将用一个空格 替换每一条注释。
int /*这看起来不像是一个空格*/ fox;
将变成
int fox;
16.2 明示常量: #define
可以使用#define定义明示常量(符号常量)...//const更好
每行#define 由3部分组成
#define + 宏 + 替换列表
预处理器在程序中找到宏就会用替代体 替代该宏。
16.2.1 记号
可以把宏的替换体看作是记号型字符串。C预处理器记号是宏定义的替换提中单独的”词”。
16.2.2 重定义常量 (通常不需要也不要这样做)
16.3 在#define中使用参数
使用参数 用#define创建类似函数的 类函数宏。 //但并不是函数,所谓的类函数只是简单的替换16
#define MEAN(x,y) (((x) + (y))/2)
16.3.1 用宏参数创建字符串:#运算符
例子:
#define PSQR(X) printf("The square of X is %d.\n",((X)*(X)) );
使用
PSQR(8);
输出:
The square of X is 64.
C允许字符串包含宏参数,
#include<stdio.h> #define PSQR(x) printf("The square of " #x " is %d.\n", ((x)*(x))) int main(void) { int y = 5; PSQR(y); PSQR(2+4); return 0; }
16.3.2 预处理器粘合剂:##运算符
##运算符把两个记号合并成一个记号:
#define XNAME(n) x## n
然后
XNAME(4)将会展开为x4
16.3.3 变参宏:...和__VA__ARGS__
#define PR(...) printf(__VA_ARGS__)
16.4 宏和函数的选择
似乎没必要使用宏替代函数。
16.5 文件包含:#include
预处理器发现#include指令时,会查看后面的文件名并把文件内容包含到当前文件中。
相当于把 被包含的文件的全部内容输入到源文件#include指令所在的位置。
#include指令有两种形式:
#include<stdio.h>
#include"mystuff.h"
16.5.2 使用头文件
头文件最常用的形式如下:
明示常量
宏函数
函数声明
结构模板定义
类型定义
16.6 #undef
“取消“ 已定义的#define指令
#define LIMIT 400
#undef LIMIT //取消了之前的定义,现在可以重新定义LIMIT
16.6.2 从C预处理器角度看已定义
16.6.3 条件编译
1.#ifdef 、#else和#endif指令
条件编译示例:
#ifdef MAVIS //如果已经define 了 MAVIS
#include"hores.h"
#define STABLES 5
#else //否则
#include"cow.h"
#define STABLES 15
#endif //条件编译结束
2.#ifnde指令似
#ifndef 和#ifdef指令类似
但ifndef指令判断的时后面的标识符是否是未定义的。
使用多个头文件时,#ifndef 可以防止重复编译、重复包含
#ifndef NAMES_H_
#define NAMES_H_
//...name.h的具体内容,函数原型,明示常量等。
...
#endif
//注:#pragma once 也可以防止重复包含。
16.6.4 预定义宏
16.6.5 #line和#error 重置行号 和 发出错误消息
16.6.6 #pragma
#pragma c9x on //使用C9X 标准(C99)
16.6.7 泛型选择
C11新增了一种表达式:泛型选择表达式。可根据表达式的类型选择一个值。
#ifndef NAMES_H_
例:
_Generic(x, int:0, float:1, double:2, default:3)
_Generic是C11的关键字,他后面的括号的第一项是一个表达式(例子种是x),后面是类型+:+值(如 float:1)
16.9 内联函数 //可能会加快调用函数的速度
定义:
inline static void eatline()
{
while(getchar() !='\n')
continue;
}
int main()
{
...
eatline();
}
16.8 _Noreturn函数(C11)
_Noreturn函数说明符,表示完成函数后不返回主调函数(No return)
16.9 C库
16.9.1 访问C库
1.自动访问
2.文件包含 #include
3.库包含
16.9.2 使用库 描述
阅读(库函数)文档的关键是看懂函数头
16.10 数学库 (math.h)
16.11 通用工具库
通用工具库包含各种函数,包括随机数生成,查找,排序等。