C预处理器及预处理器指令

预处理器: 数组

   编译程序以前,先由预处理器检查程序,根据程序中使用的预处理器指令,预处理器用符号缩略语所表明的内容替换程序中的缩略语。安全

   预处理器能够根据包含其余文件,还能够选择让编译器处理哪些代码,预处理器不能理解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.类型定义

相关文章
相关标签/搜索