预处理器: 数组
编译程序以前,先由预处理器检查程序,根据程序中使用的预处理器指令,预处理器用符号缩略语所表明的内容替换程序中的缩略语。安全
预处理器能够根据包含其余文件,还能够选择让编译器处理哪些代码,预处理器不能理解C,它通常是接受一些文本并将其转换成其余文本函数
1.#define 的用法spa
定义: .net
宏 #define 预处理指令 可出如今源文件的任何地方 指令定义的做用于从定义出现的位置开始直到文件的结尾。指针
预处理器在程序中发现了宏的实例后,总会用实体代替该宏,从宏变成最终的替换文本的过程称为宏展开。开发
预处理器发现程序中的宏后,会用它的等价替换文本代替宏。若是该字符还包括宏,则继续替换这些宏。字符串
const关键字获得了C的支持,这确实提供了一种建立常量的更灵活的方法,使用const能够建立全局变量和局部变量、数字常量、数组常量和结构常量,另外一方面宏常量能够用来指定标准数组大小并做为const值得初始化值。get
#define LIMIT 20编译器
const int LIM =50;
static int data1[LIMIT]; //合法
static int data2[LIM]; //无效
const int LIM2 = 2 * LIMIT; //合法
const int LIM3 = 2* LIM; // 无效
(1)简单的用法
#define MAXTIME 1000
一个简单的MAXTIME就定义好了,它表明1000,若是在程序里面写
if(i<MAXTIME){.........}
编译器在处理这个代码以前会对MAXTIME进行处理替换为1000。
这样的定义看起来相似于普通的常量定义CONST,但也有着不一样,由于define的定义更像是简单的文本替换,而不是做为一个量来使用。
(2)函数定义(时刻注意#define只是进行文本替换 而不进行任何编译处理)
define能够像函数那样接受一些参数,以下
#define max(x,y) (x)>(y)?(x):(y);
这个定义就将返回两个数中较大的那个,看到了吗?由于这个“函数”没有类型检查,就好像一个函数模板似的,固然,它绝对没有模板那么安全就是了。能够做为一个简单的模板来使用而已。
可是这样作的话存在隐患,例子以下:
#define Add(a,b) a+b;
在通常使用的时候是没有问题的,可是若是遇到如:c * Add(a,b) * d的时候就会出现问题,代数式的本意是a+b而后去和c,d相乘,可是由于使用了define(它只是一个简单的替换),因此式子实际上变成了
c*a + b*d
另外举一个例子:
#define pin (int*);
pin a,b;
本意是a和b都是int型指针,可是实际上变成int* a,b;
a是int型指针,而b是int型变量。
这是应该使用typedef来代替define,这样a和b就都是int型指针了。
因此咱们在定义的时候,养成一个良好的习惯,建议全部的层次都要加括号。
(3)#define 多行定义
define能够替代多行的代码,例如MFC中的宏定义(很是的经典,虽然让人看了恶心)
#define MACRO(arg1, arg2) do { /
/* declarations */ /
stmt1; /
stmt2; /
/* ... */ /
} while(0) /* (no trailing ; ) */
关键是要在每个换行的时候加上一个"/"
(4).在大规模的开发过程当中,特别是跨平台和系统的软件里,define 最重要的功能是条件编译。
就是:
#ifdef WINDOWS
......
......
#endif
#ifdef LINUX
......
......
#endif
#ifdef XXX…(#else) …#endif
例如 #ifdef DV22_AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif
#ifndef XXX … (#else) … #endif
能够在编译的时候经过#define设置编译环境
(5).如何定义宏、取消宏
//定义宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]
普通宏
#define PI (3.1415926)
带参数的宏
#define max(a,b) ((a)>(b)? (a),(b))
关键是十分容易产生错误,包括机器和人理解上的差别等等。
(6)头文件(.h)能够被头文件或C文件包含
重复包含(重复定义)
因为头文件包含能够嵌套,那么C文件就有可能包含屡次同一个头文件,就可能出现重复定义的问题的。
经过条件编译开关来避免重复包含(重复定义)
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件内容
…
#endif
此功能也可使用#pargam once 指令代替
(7)define中的三个特殊符号:#,##,#@
===========================================================
1. #define Conn(x,y) x##y
2. #define ToChar(x) #@x
3. #define ToString(x) #x
(1)x##y表示什么?表示x链接y,举例说:
1. int n = Conn(123,456); /* 结果就是n=123456;*/
2. char* str = Conn("asdf", "adf"); /*结果就是 str = "asdfadf";*/
(2)再来看#@x ,其实就是给x加上单引号,结果返回是一个const char。举例说:
char a = ToChar(1);结果就是a='1';
作个越界试验char a = ToChar(123);结果就错了;
可是若是你的参数超过四个字符,编译器就给给你报错了!
error C2015: too many characters in constant :P
(3)最后看看#x,估计你也明白了,他是给x加双引号
char* str = ToString(123132);就成了str="123132";
宏与函数的选择:
宏与函数间的选择其实是时间与空间的权衡,宏产生内联代码 也就是说在程序中产生语句,若是使用了宏20次 则会把20行代码插入程序中,若是使用函数20次,那么程序中只有一份函数语句的拷贝,所以节省了空间,另外一方面,程序的控制必须转移到函数中并随后返回调用程序,所以这比内联代码花费的时间多。
宏的一个有点事不检查其中的变量类型
C 标准的预约义宏
_ _DATE_ _ 进行预处理的日期 (“Mmm dd yyy”形式的字符串文字)
_ _FILE_ _ 表明当前源代码文件名的字符串文字
_ _LINE_ _ 表明当前源代码文件中的行号的整数常量
_ _STDC_ _ 设置为1 时 表示该实现遵循C标准
_ _STDC_HOSTED_ _ 在本机环境设置为1,不然设置为0
_ _STDC_VERSION_ _ 在C99是设置为199901L
_ _TIME_ _ 源文件编译时间 格式为"hh:mm:ss"
2.#include
(1)两种使用形式
#include<stdio.h>
#include "myStuuff.h"
在Unix系统中 尖括号告诉预处理器在一个或多个标准系统目录中寻找文件, 双引号告诉预处理器如今当前目录中寻找文件,而后再标准位置选在文件
(2)使用头文件
头文件中最多见的形式包括:
a.明显常量
b.宏函数
c.函数声明
d.结构模板定义
e.类型定义