预处理
C语言对源程序处理的四个步骤
预处理、编译、汇编、链接
预处理
(1)文件包含 #include
(2)宏定义 #define
(3)条件编译 #if #endif
(4)一些特殊作用的预定义宏
1.文件包含 #include
• #include< >与#include" "
• <>表示系统直接按系统指定目录检索。
• ""表示系统先在file1.c所在的当前目录找file1.h,如果找不到,再按系统指定的目录检索。
• #include<>常用于包含库函数的头文件。
• #include""常用于包含自定义的头文件。
• 理论上#include可以包含任意格式的文件(.c/.h等),但我们一般用于头文件的包含。
2.宏定义 #define:用指定的符号代替指定的信息。
• 宏名一般用大写,以便于与变量区别。
• 字符串可以是常量、表达式等。
• 宏定义不做语法检查,只有在编译被宏展开后的源程序才会报错。
• 宏定义不是C语言,不在行末加分号。
• 宏名有效范围为从定义到本源文件结束。
• 可以用#undef命令终止宏定义的作用域。
• 在宏定义中,可以引用已定义的宏名。
• 不带参数的宏定义
#define 宏名 字符串
例如:#define PI 3.1415926
- 在编译处理时,将程序中在该语句以后出现的所有的PI都用3.14159626代替。
- 这种方法使用户能以一个简单的名字代替一个长的字符串。
- 在预编译时将宏名替换成字符串的过程称为“宏展开”。
- 宏定义,只在宏定义的文件中起作用。
- 在编译处理时,将程序中在该语句以后出现的所有的PI都用3.14159626代替。
#include <stdio.h> #define PI 3.1415926 int main(int argc,char *argv[]) {
float L,S,R,V; printf("Input R:"); scanf("%f",&R); L = 2.0f * 2PI * R; S = PI * R *R; V = 4.0f/3 * PI * R * R * R; printf("L = %.4f,S = %.4f,V = %.4f",L,S,V); return 0; }
• 带参数的宏定义
- 格式:#define 宏名(形参表) 字符串
- 调用:宏名(形参表)
- 宏展开:进行宏替换
- 使用带参数的宏定义最好加上括号,避免宏的副作用。
#define S(a,b) a*b
.
.
Area = S(3,2); //用3和2分别代替宏定义中的形式参数a和b即S(3*2),因此赋值语句展开为:Area = 3*2
#include <stdio.h> #define SQ_1(Y) (Y)*(Y) #define SQ_2(Y) Y*Y int main(int argc,char *argv[]) {
int a = 0,num_1 = 0,num_2 = 0; scanf("%d",&a); num_1 = SQ_1(a+1); //num_1 = (a+1)*(a+1) num_2 = SQ_2(a+1); //num_2 = a+1*a+1 printf("num_1 = %d",num_1); printf("num_2 = %d",num_2); return 0; }
3.条件编译 #if #endif
• 条件编译:一般情况下,源程序中所有的行都参加编译,但有时希望对部分源程序行只在满足一定条件时才编译,即对这部分源程序行指定编译条件。
1.测试存在:
#ifdef 标识符
程序段 1
#else
程序段 2
#endif
2.测试不存在:
#ifndef 标识符
程序段 1
#else
程序段 2
#endif
3.根据表达式定义:
#if 表达式
程序段 1
#else
程序段 2
#endif
• 条件编译的作用:
1.防止头文件被重复包含引用
#ifndef __MAIN_H__
#define __MAIN_H__
需要声明的变量、函数
宏定义
结构体
#endif
2.软件裁剪
同样的C代码,条件选项不同可以编译出不同的可执行程序。
//将字母全改为大写输出或全改为小写输出 #include <stdio.h> #define BIG 1 int main(int argc,char *argv[]) {
char str[20] = "C Language",string; int i = 0; while((string = str[i++]) != '\0')
{
#if BIG if(string >= 'a' && string <= 'z') string = string - 32; #else if(string >= 'A' && string <= 'Z') string = string + 32; #endif printf("%c",string); }
return 0; }
4.一些特殊的预定宏
C编译器提供了几个特殊形式的预定义宏,在实际编程中可以直接使用。
//__FILE__ 宏所在文件的源文件名 //__LINE__ 宏所在行的行号 //__DATE__ 代码编译的日期 //__TIME__ 代码编译的时间 //__FUNCTION__ 宏所在函数的函数名 #include <stdio.h> int main(int argc,char *argv[]) { printf("FILE = %s",__FILE__): printf("LINE = %d",__LINE__); printf("DATE = %s",__DATE__); printf("TIME = %s",__TIME__); printf("FUNCTION = %s",__FUNCTION__); return 0; }