编译预处理指令
- #开头的是编译预处理指令
- 它们不是C语言的成分,但是C语言程序离不开它们
- #define来定义一个宏
头文件header file
一个大程序,通常分为多个模块,并由多个程序员分别编程。
有了文件包含处理功能,就可以将各个模块的数据(如符号常量和数据结构)或函数,集中到一个单独的头文件中。
这样,只要将所需文件包含进来,即可使用其中数据或调用其中函数,不必再重复定义它们,从而减少重复劳动
头文件只要是文本文件,文件名的后缀可以是任何合法的后缀名
当源程序中包含头文件时,可以对其中包含的头文件进行修改,但修改后必须对该源程序重新进行编译连接
宏命令行不是C语句
#include<包含该库函数的头文件>
每一个以#开头的行称为编译预处理行
标准输入输出头文件
将stdio.h嵌入该行为作为源程序的一部分
输出格式符:
%c : char
%s : 字符串 char*
%d : int (十进制)
%o : int (八进制)
%x : int (十六进制)
%u : int (不带符号十进制)
%f : float
%lf : double
%e: float ,double(指数形式)
其他:宽度限定(在%后加数字)
左对齐格式符(在%和数字之间加‘-’)
数学函数库
#include<math.h>
⒈ 余弦函数 double cos(double x)
⒉ 正切函数 double tan(double x)
⒊ 反余弦函数 double acos(double x)
⒋ 平方根函数 double sqrt(double x)
⒌ 指数函数 double pow(double x,double y)
⒍ e的指数函数 double exp(double x)
⒎ 绝对值函数 double fabs(double x)
⒏ 以e为底的对数函数 double log(double x)
⒐ 以10为底的对数函数 double log10(double x)
字符分类函数
C character classification functions
#include <ctype.h>
⒈ 检查字母、数字字符函数 int isalnum(char)
isalnum(’\x20’) 为0,isalnum(’A’) 为非0;
⒉ 检查字母函数 int isalpha(char)
若为英文字母,返回非0(小写字母为2,大写字母为1)
若不是字母,返回0。
⒊ 检查数字字符函数 int isdigit(char)
⒋ 检查可打印字符函数 int isgraph(char)
⒌ 检查小写字母函数 int islower(char)
⒍ 小写字符转换为大写字符函数 char toupper(char)
常用函数 standard library
#include <stdlib.h>
1.随机数发生器函数int rand( void )
2.初始化随机数发生器函数void srand(unsigned)
3.终止程序运行函数void exit(int a)
一个C程序由一个或多个函数组成 必须包含main()函数
宏定义指令 #define
#define PI 3.1415926
/*PI的作用域*/
#undef PI
宏定义tip:
- “PI” (无引号)
- P I (无空格)
- 最好用capital letter
#define <名字> <值>
在C语言的编译器开始编译之前,编译预处理程序(cpp)会把程序中的名字换成值
不占用运行时间
如果一个宏的值超过一行,最后一行之前的行末需要加
宏值后面出现的注释不会被当作宏的值的一部分
#define _DEBUG
没有值的宏
这类宏是用于条件编译的,后面有其他的编译预处理指令来检查这个宏是否已经被定义过了
预定义的宏
__LINE__
行数
__FILE__
文件名
__DATE__
日期
__TIME__
时间
__STDC__
整数类型的极限宏
#include<stdio.h>
#include<limits.h>
int main() {
printf("minimum short int is:%d\n", SHRT_MIN);
printf("maximum short int is:%d\n", SHRT_MAX);
printf("maximum unsigned short int is:%d\n", USHRT_MAX);
printf("minimum int is:%d\n", INT_MIN);
printf("maximum int is:%d\n", INT_MAX);
printf("maximum unsigned int is:%d\n", INT_MIN);
printf("minimum long int is:%d\n", LONG_MIN);
printf("maximum long int is:%d\n", LONG_MAX);
printf("maximum unsigned long int is:%lu\n", ULONG_MAX);
return 0;
}
像函数的宏
#define cube(x) ((x*(x)*(x))
括号问题
在替换带参数的宏命,圆括号必不可少
#include<stdio.h>
#define RADTODEG1(x) (x*57.29578)
#define RADTODEG2(x) (x)*57.29578
int main(int argc, char const* argv[])
{
printf("%f\n", RADTODEG1(5 + 2));
printf("%f\n", 180/RADTODEG1(1));
return 0;
}
运行实况
(5+2*57.29578)
180/(1)*57.29578
正确写法
#define RADTODEG(x) ((x)*57.29578)
带参数的宏
#define MIN(a,b) ((a)>(b)?(b):(a))
也可以组合(嵌套)使用其他宏
- 在大型程序的代码中使用非常普遍
- 可以非常复杂,如“产生”函数
- 在#和##这两个运算符的帮助下
- 没有类型检查
- 部分宏会被inline函数替代
分号?
#include<stdio.h>
#define PRETTY_PRINT(msg) printf(msg)
int main() {
int n = 12;
if (n < 10)
PRETTY_PRINT("N IS LESS THAN");
/*不加分号,会影响else语句的运行*/
else
{
PRETTY_PRINT("N is");
}
}
带参数的宏域函数有何异同点
-
函数调用时,先求出实参表示式的值,再代入形参
-
使用带参数的宏知识进行简单的字符替换
-
函数调用是在程序运行时处理的,分配临时的内存单元
-
宏展开则是在编译时行进的,不进行内存单元的分配,不进行值的传递