——Java培训、Android培训、iOS培训、.Net培训、期待与您交流!——
预处理指令
1、C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译
2、为了区分预处理指令和一般的C语句,所有预处理指令都以符号”#”开头,并且结尾不用分号
3、宏名一般用大写或者以k开头,变量名一般用小写
4、C语言提供的预处理指令主要有:宏定义、文件包含、条件编译
宏定义
一般分为不带参数的宏定义和带参数的宏定义
不带参数的宏定义
1、一般形式
#define 宏名 字符串
例:#define ABC 10
右边的字符串也可以省略,比如#define ABC
2、作用
它的作用是在编译预处理时,将源程序中所有”宏名”替换成右边的”字符串”,常用来定义常量。
例:
#include <stdio.h>
#define Count 4
int main()
{
int ages[Count] = {1, 2, 67, 89};
for ( int i = 0; i<Count; i++)
{
printf("%d\n", ages[i]);
}
return 0;
}
输出结果:
1
2
67
89
3、作用域
预处理指令可以出现在程序的任何位置
预处理指令的作用域:从编写指令的那一行开始,一直到文件结尾,可以用#undef取消宏定义的作用
例:
#include <stdio.h>
#define Count 4
int main()
{
int ages[Count] = {1, 2, 67, 89};
for ( int i = 0; i<Count; i++)
{
printf("%d\n", ages[i]);
}
#undef Count; // 从此行开始取消宏定义的作用
return 0;
}
带参数的宏定义
1、定义格式:
#define 宏名(参数列表) 字符串
#define sum(v1, v2) ((v1)+(v2))
2、使用注意—括号
例:定义平方的时候不加括号
#include <stdio.h>
#define pingfang(a) a*a // 未加括号
int main()
{
int c = pingfang(5+5); // c = 5+5*5+5 = 35
printf("c is %d\n", c);
return 0;
}
输出结果:
c is 35
#include <stdio.h>
#define pingfang(a) ((a)*(a)) // 加括号
int main()
{
int c = pingfang(5+5); // c = (5+5)*(5+5) = 100
printf("c is %d\n", c);
return 0;
}
输出结果:
c is 100
3、带参数的宏定义与函数的区别
1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行,所以带参数的宏比函数具有更高的执行效率
条件编译
只有当程序的其中一部分代码在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行)
基本用法
// 条件是对宏定义进行判断
#if 条件1
...code1... // 如果条件1成立,就把code1代码编译进去
#elif 条件2
...code2... // 如果条件2成立,就把code2代码编译进去
#else
...code3... // 如果条件3成立,就把code3代码编译进去
#endif // #endif不能少
例:
#include <stdio.h>
#define A 5
int main()
{
#if (A == 10)
printf("a是10\n");
#elif (A == 5)
printf("a是5\n");
#else
printf("a其他值\n");
#endif
return 0;
}
运行结果:
a是5
if defined()和#if !defined()
判断是否定义过某个宏
例:
// 如果定义了宏A,编译code1
#if defined(A)
...code1...
#endif
// 如果没有定义宏A,编译code2
#if !defined(A)
...code2...
#endif
ifdef()和#ifndef()
#ifdef的使用和#if defined()的用法基本一致
// 如果定义了宏A,编译code1
#ifdef A
...code1...
#endif
#ifndef又和#if !defined()的用法基本一致
// 如果没有定义宏A,编译code2
#ifndef A
...code2...
#endif
文件包含
一般形式
1、第1种形式
#include <文件名>
直接到C语言库函数头文件所在的目录中寻找文件
2、第2种形式
#include “文件名”
系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找
< >表示系统自带的文件,” “表示自定义的文件
使用注意
#include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如 a.h 包含 b.h,b.h 包含 a.h
关键字typedef
作用:给已经存在的类型起一个新的名称
使用场合
基本数据类型
例:
#include <stdio.h>
typedef int MyInt; // 给int起了个别名Myint
int main()
{
MyInt a = -10;
printf("%d", a);
return 0;
}
指针
#include <stdio.h>
// 给指针类型char *起一个新的类型名称String
typedef char * String;
int main()
{
String str = "This is a string!";
printf("%s", str);
return 0;
}
运行结果:
This is a string!
注意:“*”不能少
结构体
1、方式1
struct Student
{
int age;
};
typedef struct Student MyStu;
2、方式2
typedef struct Student
{
int age;
} MyStu;
枚举
1、方式1
enum Sex {Man, Woman};
typedef enum Sex MySex;
2、方式2
typedef enum {
Man,
Woman
} MySex;
指向函数的指针
#include <stdio.h>
typedef int (*MyPoint)(int, int);
int minus(int a, int b)
{
return a - b;
}
int sum(int a, int b)
{
return a + b;
}
int main()
{
// 定义一个指向函数sum的指针p
MyPoint p = sum;
// 定义一个指向函数minus的指针p2
MyPoint p2 = minus;
// 利用指针变量p调用sum函数
int a = (*p)(4, 5);
int b = (*p)(10, 3);
printf("%d,%d",a,b);
return 0;
}
运行结果:
9,7
typedef与#define
例:
typedef char *String1;
String1 str1, str2;
/*
经过typedef处理后,String1也算是一种数据类型,所以第3行代码相当于:
String1 str1;
String1 str2;
由于String1就是char *,所以上面的两行代码等于:
char *str1;
char *str2;
*/
#define String2 char *
String2 str3, str4;
/*
因为宏定义纯粹是字符串替换,用char *代替String2,所以相当于:
char * str3, str4;
其实也就相当于:
char * str3;
char str4;
*/
可以看出,只有str4是基本数据类型,str1、str2、str3都是指针类型。
所以,以后给类型起别名,最好使用typedef,而不是使用#define