黑马程序员---C语言学习笔记之预处理指令、宏和条件编译
来源:互联网 发布:淘宝不给发票怎么应对 编辑:程序博客网 时间:2024/05/16 06:17
一、预处理指令的概念及分类
1.基本概念
以“#”号开头指令都称为【预处理指令】。如包含命令#include等。在源程序中这些命令都放在函数之外。而且一般都放在源文件的前面,他们称为【预处理部分】
所谓预处理是指在进行编译的第一道扫描(词法扫描和语法扫描)之前所做的工作,预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分做处理,处理完毕自动进入对源程序的编译。
C语言提供了多种预处理功能。如宏定义,文件包含,条件编译等。合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。
二、宏的概念及无参宏定义方法
1.宏的概念
被定义为“宏”的标识符称为“宏名”,在编译预处理时,都用宏定义中的字符串取代换,这称为“宏代换”或“宏展开”
例如 #define Row 10 //此处Row就是一个宏
宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。在C语言中,“宏”分为【有参宏】和【无参宏】
无参宏的宏名不带参数,其定义一般形式为:
#define标识符字符串
其中"#"表示这是一掉预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”位所定义的宏名。“字符串”可以使常熟,表达式、格式串等
例如:
//定义一个宏#define PI 3.1415926#define Area PI*4#include <stdio.h> int main(int argc, const char * argv[]){ printf("area = %0.4f",Area);//预处理时,Area会被替换成3.1415926*4 return 0;}
【注意】
1、宏定义式一个预处理指令,结尾不需要加“;”
2、宏定义替换问题
例如:
//定义一个宏#define PI 3.1415926#define Sum a*b+2*b#include <stdio.h> int main(int argc, const char * argv[]){ int a = 2,b =3; printf("a2*Sum+ 3*Sum =%0d\n",2*Sum+ Sum);//预处理时,2*Sum+ Sum会被替换成2*a*b+2*b+a*b+2*b = 30而不是2*(a*b+2*b) +(a*b+2*b) = 36. printf("2*a*b+2*b+a*b+2*b = %d\n", 2*a*b+2*b+a*b+2*b); printf("2*(a*b+2*b) +(a*b+2*b) = %d", 2*(a*b+2*b) +(a*b+2*b)); return 0;}
打印结果:
a2*Sum+ 3*Sum = 30
2*a*b+2*b+a*b+2*b = 30
2*(a*b+2*b) +(a*b+2*b) = 36
三、有参宏的定义和使用方法
1、有参宏的定义方法
C语言允许宏带有参数,在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数,对带参数的宏,在调用中,不仅要宏展开,而且要用实参取代替形参。
带参宏定义的一般形式为:
define 宏名(参数表) 字符串
例如:
//定义一个带参宏#define Add(x,y) x+y#include <stdio.h> int main(int argc, const char * argv[]){ printf("x + y = %d", Add(10, 20)); return 0;}
打印结果:
x + y = 30
2、注意事项
1)宏的形参之间可以出现空格,但是【宏名】和【形参】之间不能出现空格
例如:
#define Add (x,y) x+y //报错#define Sub(x, y) x + y //不报错
2)在带参宏定义中,形式蚕食不分配内存单元,因此不必做类型定义,而宏调用中的实参有具体值,要用他们去代换形参,因此必须做类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”,而带参宏中,只是符号代表,不存在值传递的问题。
3)在宏定义中的形参是标识符,而宏调用的实参可以是表达式
4)在宏定义中,【字符串内的形参通常要用括号括起来】以避免出错,
例如:
#define Mul(x,y) x*y #include <stdio.h> int main(int argc, const char * argv[]){ int a = 2, b = 3; printf("x + y = %d", Mul(a + b, a*b)); return 0;}
打印结果:
x + y = 20
期待结果:(2+3)*(2*3) =30,但是宏展开的时候替换成了2+3*2*3 = 20
因此【字符串内的形参通常要用括号括起来】以避免出错,
如下:
#define Mul(x,y) (x)*(y) #include <stdio.h> int main(int argc, const char * argv[]){ int a = 2, b = 3; printf("x + y = %d", Mul(a + b, a*b)); return 0;}
打印结果:
x + y = 30
四、typedef和#define的区别
1、typedef和#define的区别
例如:
//定义一个宏#defineMYINT int*//给int型起一个别名typedef int* MYINT2; #include <stdio.h> int main(int argc, const char * argv[]){ //使用宏定义变量 int num = 20; MYINT a, b;//a是一个指针,b是一个普通变量,在宏展开的时候替换为int *a,b a = # printf("a = %d\n",*a); //b =# //printf("b = %d\n",*b);//报错 b = num; printf("b = %d\n",b);//打印结果b = 20 //使用别名定义变量,不是简单的替换字符串,而是给类型起了个别名 MYINT2 c, d; c = # //d = num; //报错 d = # //不会报错 printf("c = %d",*c); return 0;}
五、条件编译的概念及优点
1.为什么要使用条件编译?
1)按不同的条件取编译不同的程序部分,因而产生不同的目标代码文件,有利于程序的一直和调试
2)条件编译当然也可以用条件语句来实现,但是用条件语句将会对整个源程序进行编译,生成的目标代码程序很长,而采用了条件编译,则根据条件只编译其中的程序段1或程序段4,生成的目标程序较短。
2.条件编译
发生在预处理阶段,在编译前做的事情
【核心】:根据条件编译指定的代码
条件不同,编译的部分也不同,生成的目标文件(.o)大小也不同
#define score 89#include <stdio.h> int main(int argc, const char * argv[]){ /* intscore = 89; //用if条件语句实现,编译后(.o)文件的大小是1,172 bytes score /=10; if (score < 6) { printf("E"); } else if (score < 7) { printf("D"); } else if (score < 8) { printf("C"); } else if (score < 9) { printf("B"); } else{ printf("A"); }*///使用条件编译,(.o)文件 836 bytes#if score < 6 //此处不能使用普通变量,要用宏定义 printf("E");#elif score < 7 printf("D");#elif score < 8 printf("C");#elif score < 9 printf("B");#else printf("A");#endif //这个必须有,有#if配对 return 0;}
3、#ifdef用来判断某个宏是否定义
例如:
int a = 0;#ifdef AMOS//检测宏DEBUG1是否定义,若果定义了,a=10,对应的#ifndef,如果没有定义 a = 10;#else a = 100;#endif printf("a = %d\n",a);
4、使用条件编译调试程序
#define AMOS 0#include <stdio.h>//使用条件编译调试程序 #if AMOS == 1//显示调试信息#define Log(format,...) printf(format,## __VA_ARGS__);#else//不显示调试信息#define Log(format,...)#endif int main(int argc, const char * argv[]){ int a = 0;#ifdef DEBUG1 //检测宏DEBUG1是否定义,若果定义了,a=10,对应的#ifndef,如果没有定义 a = 10;#else a = 100;#endif Log("------------------>a = %d\n", a); return 0;}
打印结果:
当AMOS = 1时:
------------------>a= 100
当AMOS = 0时:
没有打印任何信息
- 黑马程序员---C语言学习笔记之预处理指令、宏和条件编译
- 黑马程序员--IOS学习笔记总结 预处理指令(宏定义、条件编译、文件包含)
- 【黑马程序员】C语言学习笔记(3)-预处理指令
- 黑马程序员——C语言笔记之预处理指令
- 黑马程序员-----C语言学习之预处理指令
- 黑马程序员 C语言------预处理指令学习
- 【黑马程序员】C语言学习笔记之预处理指令(十四)
- 黑马程序员-----c语言学习笔记之预处理指令、函数、变量
- 黑马程序员——C语言笔记之预处理指令和模块化编程
- 【黑马程序员】iOS学习之路——C语言之宏定义、条件编译和条件包含及typedef
- C语言的预处理和条件编译指令
- 黑马程序员--学习C语言条件编译
- C语言-预处理指令2-条件编译
- 【C语言】预处理指令—条件编译
- C语言 预处理指令 2条件编译
- C语言预处理指令:宏、条件编译、文件包含
- 黑马程序员——12-C语言之预处理指令
- C语言学习入门 (六) 预处理指令:宏、条件编译、文件包含
- 架构师
- React-Native测试报告
- Valid Number
- UIDynamic-动力效果
- Eclipse使用servletActionContect.getResquet出错解决方法:
- 黑马程序员---C语言学习笔记之预处理指令、宏和条件编译
- JNDI全面总结
- 使用gdb和core dump迅速定位段错误
- SpringMVC(1)
- Photon服务器引擎(二)socket/TCP/UDP基础及Unity聊天室的实现
- BZOJ2763: [JLOI2011]飞行路线
- SpringMVC(二)
- HDU 2892 area (多边形和圆面积并--基础题)
- Python CGI与Apache的配置