(c/c++学习笔记十一)预处理命令
来源:互联网 发布:阿里云机房 编辑:程序博客网 时间:2024/06/05 14:14
预处理是指在进行编译的第一遍扫描(语法扫描和语法分析)之前所做的工作。预处理是C语言的一个重要功能,它由预处理器负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对程序中的预处理部分作处理,处理完毕后自动进入对源程序的编译。C语言提供了多种预处理功能,如宏定义、文件包含、条件编译等。
一.宏
C语言允许用一个表示法来表示一个字符串,称为“宏”。被定义为“宏”的表示符称为“宏名”,对程序中所有出现的“宏名”,都用宏定义中的字符串去替换,这称为“宏替换”和“宏展开”。
1.无参数宏
定义的一般形式为: #define 标示符 字符串
例:
#define ADD (a+b) //定义一个宏 不用加分号 如果有分号则一起替换int main(int argc, char *argv[]){ int a = 5, b = 3, c; c = 2*ADD; //宏展开为 c=2*(a+b); 注意括号不能少 printf("c=%d\n",c); //输出 c=16 }宏定义使用宏明表示一个字符串,在宏展开时又以该字符串取代宏名,这是一种简单的替换,字符串中可以包含任何字符,可以是常数,也可以使表达式,预处理程序对它不作任何检查,如有错误,只能在编译已被宏展开后的程序是发现。
宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束,要终止其作用域可以使用#undef命令
例:
#define PI 3.14int main(int argc, char *argv[]){double pi = PI;printf("PI=%f\n",PI);}#undef PIvoid function(){double pi = PI; //错误 已经取消宏定义printf("PI=%f\n",PI);}宏明在源程序中若用引号括起来,则预处理程序不对其做宏替换
宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏明。在宏展开时由预处理程序层层替换。
例:
#define PI 3.14#define N 2*PI*r int main(int argc, char *argv[]){double r = 5;double n = N; //展开为 n=2*3.14*rprintf("n=%f",n);}
注意#define和typedef的区别,宏是预处理完成的,typedef是在编译时处理的。typedef不是简单的替换,而是对类型说明符重命名。
例:
#define INTPTR1 int*typedef int* INTPTR2;int main(int argc, char *argv[]){INTPTR1 a, b; //a是指针变量 b是整型变量INTPTR2 x, y; //x y都是指针变量int m = 10;a = &m;b = &m; //错误 b是整型变量x = &m;y = &m;}
二.带参数的宏
C语言允许带有参数的宏。在宏定义中的参数称为形式参数,在宏调用中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代替形参。
带参宏定义的一般形式为: #define 宏名(形参表) 字符串 调用形式为: 宏名(实参表)
例:
#define ADD(a,b) a+bint main(int argc, char *argv[]){int a = 4, b = 5, c;c = ADD(a,b); //宏展开为 c=a+bprintf("c=%d\n",c); //输出 c=9}
在带参宏定义中,形参不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用他们去替换形参因此必须做类型说明。这是与函数中的情况不同的。在函数汇中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而带参宏中,只是符合代换,不存在值传递问题。
在宏定义的形参标识符,而宏调用可以使表达式
例
#define MUT(x) (x)*(x)int main(int argc, char *argv[]){int a = 4, b;b = MUT(a+2); //宏展开 (a+2)*(a+2) 注意宏定义中参数的括号,如果没括号,则展开为 a+2*a+2,结果完全不同printf("b=%d\n",b); //输出 b=36 如果宏定定字符串中没有括号 则结果为10}
带参宏和带参函数很相似,但有本质不同,除了上面谈到的几点之外,把同一表达式用函数处理与用宏处理的结果有可能是不同的
例:(函数调用)
int MUT(int x){return (x)*(x);}int main(int argc, char *argv[]){int i = 1;while(i<=5)printf("%d\n",MUT(i++));}例(带参宏)
#define MUT(x) ((x)*(x))int main(int argc, char *argv[]){int i = 1;while(i<=5)printf("%d\n",MUT(i++));}函数调用中,i作为函数参数传入到函数内,计算完返回 i加1进入下次循环,共执行5次循环 带参宏中,宏展开为(i++)*(i++) 计算完i做两次自加操作,只循环三次
宏定义也可以来定义多个语句,在宏调用时,把这些语句又代换到源程序内。
例:
#define DEF int a = 2; int b = 3; int c = a + 2;int main(int argc, char *argv[]){DEF;printf("a=%d b=%d c=%d",a,b,c); //输出 a=2 b=3 c=40}
预处理程序提供了条件编译的功能,可以按不同的条件去编译不同的程序部分,因而产品不同的目标代码文件。这对程序的移植和调试是很有用的,条件编译有三种形式。
第一种:
#ifdef 标识符
程序段1
#else
程序段2
#endif
它的功能是,如果标识符已经被#define命令定义过则对程序段1进行编译,否则对程序段2进行编译。如果没有程序段2,本格式中的#else可以没有,即可以写为:
#ifdef 标识符
程序段1
#elseif
第二种:
#ifndef 标识符
程序段1
#else
程序段2
#endif
它的功能和第一种正相反,如果标识符未被#define命令定义过则对程序段1进行编译,否则对程序段2进行编译
此功能多用于避免头文件多重包含
第三种:
#if 常量表达式
程序段1
#else
程序段2
#endif
它的功能是,如果常量表达式的值为真(非0),则对程序段1进行编译,否则对程序段2进行编译。
- (c/c++学习笔记十一)预处理命令
- C学习笔记(十一)C预处理器和C库
- C语言程序学习(十一)笔记
- C学习笔记(十一)数组认知
- c语言学习笔记十一
- c/c++基础(十一) 预处理
- C语言学习(五)函数,预处理命令
- 【黑马程序员】C语言学习笔记(3)-预处理指令
- C/C++学习笔记六(文件系统、预处理器)
- C语言学习笔记之预处理篇
- C语言学习笔记8---预处理
- C学习笔记之预处理指令
- Objective-C 学习笔记 12 预处理程序
- 学习笔记7-C语言预处理
- C语言预处理指令学习笔记
- C语言学习笔记_6编译预处理
- C语言深度剖析学习笔记-预处理
- C中的预处理命令
- Android系统Recovery工作原理之使用update.zip升级过程分析(五)---update.zip包从上层进入Recovery服务
- 修改MyEclipse内存——-OutOfMemoryError错误
- 计算机视觉、机器学习代码示例集合
- XML的命名空间
- 不一样的下拉刷新,ZrcListView
- (c/c++学习笔记十一)预处理命令
- Maven 之 findbugs 插件
- 什么是设计模式
- 【基础算法】排序-简单排序之二(选择排序)
- Android系统Recovery工作原理之使用update.zip升级过程分析(四)---Android系统Recovery模式的工作原理
- Android打包之Eclipse打渠道包
- 关于类名大小写引发的MissingPropertyException错误
- MySQL server has gone away 问题的解决方法
- android手势处理