首页 > 其他 > 详细

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

时间:2015-08-03 19:28:41      阅读:186      评论:0      收藏:0      [点我收藏+]

预处理器: 

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

   预处理器可以根据包含其他文件,还可以选择让编译器处理哪些代码,预处理器不能理解C,它一般是接受一些文本并将其转换成其他文本

1.#define 的用法

定义: 

 宏 #define  预处理指令  可出现在源文件的任何地方 指令定义的作用于从定义出现的位置开始直到文件的结尾。

     预处理器在程序中发现了宏的实例后,总会用实体代替该宏,从宏变成最终的替换文本的过程称为宏展开。

     预处理器发现程序中的宏后,会用它的等价替换文本代替宏。如果该字符还包括宏,则继续替换这些宏。

const关键字得到了C的支持,这确实提供了一种创建常量的更灵活的方法,使用const可以创建全局变量和局部变量、数字常量、数组常量和结构常量,另一方面宏常量可以用来指定标准数组大小并作为const值得初始化值。

 #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.类型定义










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

原文:http://my.oschina.net/u/818523/blog/487172

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!