2009年1月30日星期五

简述C/C++中预处理使用

    写过C/C++代码的估计都碰到过使用预处理符的情况吧,今天我们就来简单的涉猎一下主要的也是最常用的C/C++的预处理符(非标准及很少用的就不列入,想知道的自己翻看相关文档)。

1.预处理指示符

  类似#define/#ifdef这样的都是预处理指示符,预处理指示符主要用于让源代码在不同的环境下更好的被编译。

1.1.#define

  #define大家都很熟悉了,它是一个定义宏。一般来说,他有如下两种使用方式:

QUOTE:

#define _KC  // form one
#define _KC(var) cout<<var<<endl  // form two
第一种形式定义了_KC标识符,这在全局都有效,通常会和#ifdef等一起使用。

  第二种方式则在定义标识符之后再进行替换动作,后面的cout<<var<<endl替换前面的定义符。正如你所见,可以使用参数,只需要在后面添加括号即可。并且可以有多个参数,参数间用,分隔。

  需要注意的是,#define并不支持重载(似乎是废话-。-),多次定义一个标识符会发生后面的覆盖前面的,并且某些编译器会发出Warning。

1.2.#undef

  #undef是针对#define而来的,他的职责就是干掉(移除)用#define定义的标识符。

QUOTE:

#define _KC(var) cout<<var<<endl  // former definition
// do something
#undef _KC  // remove and do not give a parameter list
#undef有两点需要注意:第一,不要加上参数列表;第二,即使一个标识符未定义,你也可以对这个标识符使用#undef。通常这是为了确保某个标识符尚未被定义。

1.3.#error

    使用#error可以在编译阶段扔出一个诊断消息并且造成编译错误,最终终止编译。

QUOTE:

#define _KC(var, avr) cout<<var<<endl<<avr<<endl

#ifdef _KC
  
#error _KC has been definition  // throw a compile-error message
#endif
在上面的代码中,由于已经定义了_KC标识符,所以会在编译阶段抛出一个编译错误,并显示“_KC has been definition”

1.4.#include

  #include用来包含头文件,有两个使用版本:

QUOTE:

#include "KC.h"
#include <iostream>
二者的据别在于,""的现在当前目录中查找,然后再到包含头文件的默认目录中查找。而<>直接在默认目录中查找。

1.5.#ifdef/#ifndef...#else...#endif

  #ifdef和#ifndef类似于使用的if语句,根据标识符的定义情况进行预编译:

QUOTE:

#define _KC

#ifdef _KC
  
#define KC "alive"
#else
  #define
KC "dead"
#endif
如果_KC标识符已经定义,则预编译紧跟其后的那行,如果未定义,则预编译#else的那段。

  #ifndef和#ifdef相反,#ifndef可以这样理解#if-not-def。

1.6.#if...#elif...#else...#endif
  #if是#ifdef和#ifndef的一般形式,#ifdef/#ifndef右边只能是定义标识符,而#if右边可以是一个常量表达式。类似的#elif的右边也需要一个常量表达式,通常#elif可以形成一个判断串。

  事实上,#ifdef和#ifndef的本质是:

QUOTE:

#ifdef == #if identifier
#ifndef == #if !identifier
2.预处理操作符
2.1.#字符串化


  #符可以格式化#define定义符的参数,使之变为字符串,代码如下:

QUOTE:

#define _KC(var) cout<<(#var)<<endl

int main()
{
  
_KC(Fuck Communist Party);  // output Fuck Communist Party
  
cout<<"Please press any to exit"<<endl;
  
getch();
  
return 0;
}
2.2.##连接符

  ##可以在预编译的时候连接两端的东西,之所以说东西,是因为他完全是机械式的连接,不仅仅可以是字符串,任何能够写出俩的都可以连接。

  比如k##c,预编译之后就是kc,不一定要是字符串,这里来一个比较BT的例子:

QUOTE:

#define _KC kf##c

int main()
{
  
int kfc = 5;
  
cout<<_KC<<endl;  // output 5
  
cout<<"Please press any to exit"<<endl;
  
getch();
  
return 0;
}
如果理解了,上面的代码你就不会觉得不可思议

3.预定义宏
3.1.__DATE__和__TIME__

  __DATE__输出编译这个源代码时刻的日期,日期格式是mm dd yy 。而类似的,__TIME__输出编译源代码时刻的时间,格式是hh mm ss比如下面的代码:

QUOTE:

cout<<"Date:"__DATE__<<"\tTime:"__TIME__<<endl;
// output Date:Jan 30 2009        Time:16:49:47
注意:源代码编译后,这些信息都被确定了下来,所以不要在你的程序中用这两个符号来显示一般的时间。

3.2.__TIMESTAMP__

  这个预定义符和上面两个类似,输出最后一次修改源代码的日期和时间,格式为Ddd Mmm Date hh:mm:ss yyyy 示例代码:

QUOTE:

cout<<__TIMESTAMP__<<endl;
//Fri Jan 30 16:54:08 2009
3.3.__FILE__和__LINE__

  __FILE__和__LINE__在调试的时候可能会有的比较多,他们输出源代码所在的文件(路径)和所在的行,通常用于调式的定位。

QUOTE:

cout<<"SRC File: "<<__FILE__<<endl<<"SRC Line: "<<__LINE__<<endl;
cout<<"Please press any to exit"<<endl;
// output
//SRC File: d:\程序设计\个人程序设计\算法&数据结构\array\main.cpp
//SRC Line: 21
4.尾声

  如此这般,主要的在预处理中会用到的指示符、操作符和宏我们都讲的差不多了。这些东西虽然不怎么起眼,但是有时候用处比较大~用得好,效果也是非常不错的~

  好了,再过几天我也要开学了,不舍ING~

--------------------EOF-------------------

Document Download:About Preprocessor.zip

没有评论:

发表评论

1、可以使用<b>、<i>、<a>等Html标志,让评论更有特色...
2、支持OpenID登录,技术达到国际先进水平。但切记,评论内容不代表本站观点!
3、当遇到“连接被重置”、“连接超时”和“此网页无法访问”等而发表不了评论的话,请多刷新几次页面,或迟三分钟后再试;
4、对你的浏览造成不便,站长在此代表全国G.FW工作人员向你鞠躬致歉!!!