C语言--预处理指令小结
2014-12-10 16:01
162 查看
C语言--预处理指令小结
预处理指令简介
1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通 常的编译2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号
3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源 程序文件
4.C语言提供的预处理指令主要有:宏定义、文件包含、条件编译
作用:它的作用是在编译预处理时,将源程序中所有"宏名"替换成右边的"字符串",常用来定义常量。
一、宏定义 #define
预处理指令:宏定义一般分为两种:带参数 和 不带参数
不带参数的宏定义
#define 宏名 字符串
比如#define ABC 10
右边的字符串也可以省略,比如#define ABC
字符串一般大写 或以k开头, 小写一般表示变量名
作用域:在代码翻译成0 和 1 之前执行,从生成开始,直到最后或遇到#undef 字符串 时结束
位置不定:可以在任何位置
用双引号 ”” 括起来的宏定义名称不翻译
例如:
#include <stdio.h> // 源程序中所有的宏名PI在编译预处理的时候都会被3.14所代替 #define PI 3.14 // 根据圆的半径计radius算周长 float girth(float radius) { return 2 * PI *radius; } int main () { float g = girth(2); printf("周长为:%f", g); return 0; }
带参数的宏定义
格式:#define 名称(参数,参数) 公式;((参数) 符号(参数))
带参数的宏在展开时,只作简单的字符和参数的替换,不进行任何计算操作。所以在定义宏时,一般用一个小括号括住字符串的参数。
每个参数都要加上小括号 例:#define sum(v1,v2) ((v1) *(v2))
与函数的区别
从整个使用过程可以发现,带参数的宏定义,在源程序中出现的形式与函数很像。但是两者是有本质区别的:1> 宏定义不涉及存储空间的分配、参数类型匹配、参数传递、返回值问题
2> 函数调用在程序运行时执行,而宏替换只在编译预处理阶段进行。所以带参数的宏比函数具有更高的执行效
#define sum(a,b) ((a) *(b)) #include <stdio.h> int main() { int c = sum(5+5, 3+4);//很明显,这里如果没有参数小括号会出错 printf("c = %d",c); }
二、条件编译
概念:在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行),这就是条件编译
基本用法
#if 条件1 ...code1... #elif 条件2 ...code2... #else ...code3... #endif1> 如果条件1成立,那么编译器就会把#if 与 #elif之间的code1代码编译进去(注意:是编译进去,不是执行,很平时用的if-else是不一样的)
2> 如果条件1不成立、条件2成立,那么编译器就会把#elif 与 #else之间的code2代码编译进去
3> 如果条件1、2都不成立,那么编译器就会把#else 与 #endif之间的code3编译进去
4> 注意,条件编译结束后,要在最后面加一个#endif,不然后果很严重(自己思考一下后果)
5> #if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义
下面是条件编译的总结:
1>#if(条件) Code… #elif(条件) Code… #else Code… #endif 2>#ifdef 宏名称 // 如果定义了这个宏则执行代码Code Code… // 如果是#ifndef,其他不变,则是如果没有定义则执行代码 #endif 3>#ifdefined (宏名称) //如果定义了这个宏则执行代码/ Code… // 如果是#if !defined,其他不变,则是如果没有定义则执行代码 #endif 例1: #include <stdio.h> // 因为都是宏定义,所以实在程序执行之前运行的,程序里的值是用不到的 // 所以必须在该宏定义执行之前进行判断,所以必须用宏定义 #define A5 intmain() { #if(A ==10) printf("a = 10\n"); #elif(A== 5) printf("a = 5\n"); #else printf("a是其他值\n"); #endif return 0; } 例2: #define A5 #include <stdio.h> int main( ) { #ifdef A//如果定义了这个宏则执行代码 printf("执行了这行语句\n"); //如果是#ifndef,其他不变,则是如果没有定义则执行代码 #endif }三、文件包含
<>是用来表示系统文件
””是用来表示自定义文件
不允许互相包含(a.h包含b.h , b.h又包含a.h)
文件的合成 假设有3个文件 test.c lisi.c lisi.h test.c想用lisi.c文件里的函数
test.c文件
#include “lisi.h”//导入lisi的文件 intmain() { int c =sum(5,8); printf(“5+8= %d\n”,c); return 0; }
lisi.c文件
int sum(int a , int b) { return a+b; }
lisi.h文件 // .h文件是放声明的文件//这加上条件编译,是防止多次导入带来的错误
#ifndef LISI_H // 判断宏定义是否存在, #define LISI_H //如果不存在则定义一个宏,宏名称最好是文件名,不易记错出乱 int sum(int a , int b); #endif四、typedef 类型
给基本类型,指针,结构体,枚举 起个 新的别名
typedef int Myint; // 此后的 Myint 就相当于 int 类型 int a; <-> Myint a;
也可定义指针类型 typedef char * String; 此后的String代表 (char *)
例如
typedef struct Student { int age; }Mystu; //或者 typedef struct Student { int age; }Mystu; int main() { struct Student stu2; Mystu stu = {32}; return 0; }
利用typedef简化定义指向函数的指针
int main() {//原版 int sum(int a, int b) { return a+b; } int (*p)(int ,int ) = sum; } //利用typedef typedef int (*Point)(int ,int);//定义一个指针Point指向函数,函数参数类型是(int ,int) int main() { int sum(int a, int b) { return a+b; } Point p = sum; }有时也要注意一下特殊情况
#define String2 char * typedef char * String int main() { //s1,s2都是char *指针 String s1,s2; s1 = "jack"; s2 = "rose"; //s3是char *指针,s4是char String2 s3,s4; /* char * s3,s4; char *s3; char s4; */ }
给指向结构体的指针起别名
#include <stdio.h> // 定义一个结构体并起别名 typedef struct { float x; float y; } Point; // 起别名 typedef Point *PP; int main() { // 定义结构体变量 Point point = {10, 20}; // 定义指针变量 PP p = &point; // 利用指针变量访问结构体成员 printf("x=%f,y=%f", p->x, p->y); return 0; }使用typedef给枚举类型起别名
// 定义枚举类型 enum Season {spring, summer, autumn, winter}; // 给枚举类型起别名 typedef enum Season Season;
也可以简化成这
typedef enum {spring, summer, autumn, winter} Season;
五、static 和 extern 对函数的影响
static
在定义函数时,在函数的最左边加上static可以把该函数声明为内部函数(又叫静态函数),这样该函数就只能在其定义所在的文件中使用。
如果在不同的文件中有同名的内部函数,则互不干扰。
* static也可以用来声明一个内部函数
extern
在定义函数时,如果在函数的最左边加上关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。
* 在一个文件中要调用其他文件中的外部函数,则需要在当前文件中用extern声明该外部函数,然后就可以使用,这里的extern也可以省略。
总结
static:表示内部 而 extern 表示外部
外部函数:定义的函数能被本文件和其他文件访问,
1>默认的都是外部函数
2>整个项目都不能有同名的外部函数
内部函数:定义的函数只能被本文件访问,其他文件不能访问
1> 允许不同文件有同名内部函数
static 对函数的作用(static不可省略),调用时可以通过调用外部函数,
此外部函数调用其内部函数
1> 定义一个内部函数
2> 声明一个内部函数
例
#include <stdio.h> static void test(); int main() { test(); return 0; } static void test() { printf("调用了test函数"); }
extern对函数的作用(extern可以省略)
1> 完整地定义一个外部函数 extern void 函数名(){}
2> 完整地声明一个外部函数 extern void 函数名();
六、static 和 extern 对变量的影响
外部变量:定义的变量能被本文件和其他文件访问
1> 默认情况下,所有的全局变量都是外部变量
2> 不同文件中的同名外部变量,都代表同一个变量
3> 声明一个外部变量:extern int a;(extern可省略)
内部变量:定义的变量只能被本文件访问,不能被其他文件访问
定义一个内部变量:static int a;
1> 不同文件中的同名变量互不影响
static 对局部变量的影响
1> 会延长局部变量的生命周期,直到程序结束才会销毁
2> 并没有改变局部变量的作用域
3> 当一个函数被调用很多次,而且函数值是不变的,则用static 定义
void test() { static double pi = 3.14;//它会保存,直到程序全部结束, double zc = 2*pi*12;// 如果不加static则,它会重复建立,销毁pi 100次 } Int main() { for(int I = 0;i < 100; i++ ) { test(); } }七、递归
递归的2个条件
1> 函数自己调用自己
2> 必须有一个明确的返回值,用于终结调用
例:设计一个函数用来计算b的n次方
#include <stdio.h> Int pow(int b, int n); int main() { int c = pow(3 , 4); printf(“%d\n”,c); return 0; } /* pow(b , 0) == 1 pow(b , 1) == b == pow(b , 0) *b pow(b , 2) == b *b == pow(b , 1) *b pow(b , 3) == b*b*b == pow(b , 2) *b 1>n为0,结果肯定是1 2>n>0, pow(b , n) == pow(b , n-1) *b */ int pow(int b, int n) { if(n <= 0) return 1; return pow(b, n-1)*b; }
相关文章推荐
- 【C语言】17-预处理指令3-文件包含
- 014-预处理指令-C语言笔记
- 【C语言】16-预处理指令2-条件编译
- 【C语言】15-预处理指令1-宏定义
- 【C语言】预处理指令—宏定义
- 【C语言】15-预处理指令1-宏定义
- [PreProccess]C语言中预处理指令的使用
- 【C语言】17-预处理指令3-文件包含
- c语言与预处理指令
- 【C语言】16-预处理指令2-条件编译
- C语言-预处理指令2-条件编译
- 黑马程序员-IOS-C语言预处理指令及杂项小计
- C语言中《预处理》小结
- 【C语言】预处理指令—条件编译
- C语言预处理指令
- C语言--预处理指令、枚举、递归函数
- 【C语言】17-预处理指令3-文件包含
- C语言常用预处理指令及常用宏
- C语言预处理指令:宏、条件编译、文件包含
- C语言第十章:结构体、枚举、预处理指令