知识大全 VC预处理指令与宏定义的妙用

Posted 指令

篇首语:努力尽今夕,少年犹可夸。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 VC预处理指令与宏定义的妙用相关的知识,希望对你有一定的参考价值。

VC预处理指令与宏定义的妙用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  刚接触到MFC编程的人往往会被MFC 向导生成的各种宏定义和预处理指令所吓倒 但是预处理和宏定义又是C语言的一个强大工具 使用它们可以进行简单的源代码控制 版本控制 预警或者完成一些特殊的功能

  一个经典的例子

  使用预处理与宏定义最经典的例子莫过于加在一个头文件中以避免头文件被两次编译 试想这种的情况 有一个文件headerfile h 它被包含在headerfile h中 同时在headerfile h 中也被包含了 现在有一个CPP文件 implement cpp 包含了headerfile h 和headerfile h

  #include headerfile h

  #include headerfile h

  假设headerfile h 中定义了一个全局变量 iglobal

  int iglobal

  在编译的时候编译器两次编译headerfile 也就会发现iglobal被定义了两次 这时就会发生变量重定义的编译错误

  传统的解决办法是使用#ifdef 以及#endif 来避免头文件的重复编译 在上面的例子中 只需要加上这么几行

  #ifndef smartnose_ _ _ _headerfile_h

  #define smartnose_ _ _ _headerfile_h

  int iglobal

  #endif

  仔细的考虑上面的宏定义 会发现当编译器编译过一次headerfile h以后 smartnose_ _ _ _headerfile_h 这个宏就被定义了 以后对headerfile h的编译都会跳过int iglobal 这一行 当然smartnose_ _ _ _headerfile_h 这个宏是可以任意定义的 但是这个宏本身不能和其它文件中定义的宏重复 所以MFC在自动生成的文件中总是使用一个随机产生的长度非常长的宏 但我觉得这没有必要 我建议在这个宏中加入一些有意义的信息 比方作者 文件名 文件创建时间等等 因为我们有时候会忘记在注释中加入这些信息

  在VC Net 中我们不会再看见这些宏定义了 因为在这里会普遍使用一个预处理指令

  #pragma once

  只要在头文件的最开始加入这条指令就能够保证头文件被编译一次 这条指令实际上在VC 中就已经有了 但是考虑到兼容性并没有太多的使用它

  源代码版本控制

  当我们为许多平台开发多个版本的时候预编译指令和宏定义也能够帮我们的忙 假设我们现在为WINDOWS 和LINUX开发了一套软件 由于这两种系统的不同 我们不得不在程序控制源代码的版本 比方内存的分配 我们可以在LINUX上使用标准C的malloc 函数 但是我们希望在 WINDOWS上使用HeapAlloc API 下面的代码演示了这种情况

  main()

  

  ……………………

  #ifdef _WINDOWS_PLATFORM

  HeapAlloc( )

  #else

  malloc( )

  #endif

  ……………………

  

  当我们在WINDOWS 平台上编译此程序的时候 只需要定义_WINDOWS_PLATFORM这个宏 那么HeapAlloc这条语句就能够起作用了 这样就能够让我们在同一个文件中为不同的平台实现不同版本的代码 同时保持程序的良好结构 在许多情况下 我们还可以为一个方法使用不同的算法 然后用宏定义来针对不同的情况选择其中的一个进行编译 这在MFC应用程序中是使用得最多的 最明显的就是文件中经常存在的

  #ifdef _DEBUG

  …………………… some code……………

  #endif

  这样的代码 这些代码在应用程序的调试版(DEBUG)中会发挥其作用

  #Pragma 指令

  在所有的预处理指令中 #Pragma 指令可能是最复杂的了 它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作 其格式一般为

  #Pragma Para

  其中Para 为参数 下面来看一些常用的参数

  message 参数 Message 参数是我最喜欢的一个参数 它能够在编译信息输出窗口中输出相应的信息 这对于源代码信息的控制是非常重要的 其使用方法为

  #Pragma message( 消息文本 )

  当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来

  当我们在程序中定义了许多宏来控制源代码版本的时候 我们自己有可能都会忘记有没有正确的设置这些宏 此时我们可以用这条指令在编译的时候就进行检查 假设我们希望判断自己有没有在源代码的什么地方定义了_X 这个宏可以用下面的方法

  #ifdef _X

  #Pragma message( _X macro activated! )

  #endif

  当我们定义了_X 这个宏以后 应用程序在编译时就会在编译输出窗口里显示 _X macro activated! 我们就不会因为不记得自己定义的一些特定的宏而抓耳挠腮了

  另一个使用得比较多的pragma参数是code_seg 格式如

  #pragma code_seg( [ section name [ section class ] ] )

  它能够设置程序中函数代码存放的代码段 当我们开发驱动程序的时候就会使用到它

  最后一个比较常用的就是上面所说的#pragma once 指令了

  VC预定义的宏

  在VC中有一类宏并不是由用户用#define语句定义的 而是编译器本身就能够识别它们 这些宏的作用也是相当大的 让我们来看第一个 也是MFC中使用得最频繁的一个 __FILE__

  当编译器遇到这个宏时就把它展开成当前被编译文件的文件名 好了 我们马上就可以想到可以用它来做什么 当应用程序发生错误时 我们可以报告这个错误发生的程序代码在哪个文件里 比方在文件test cpp中有这样的代码

  try

  

  char * p=new(char[ ])

  

  catch(CException *e )

  

  TRACE( there is an error in file %s\\n __FILE__)

  

  在程序运行的时候 如果内存分配出现了错误 那么在调试窗口中会出现there is an error in file test cpp 这句话 当然 我们还可以把这个错误信息显示在别的地方

  如果我们还能够记录错误发生在哪一行就好了 幸运的是 与__FILE__宏定义一样 还有一个宏记录了当前代码所在的行数 这个宏是__LINE__ 使用上面的两个宏 我们可以写出一个类似于VC提供的ASSERT语句 下面是方法

  #define MyAssert(x) \\

  if(!(x)) \\

  MessageBox(__FILE__ __LINE__ NULL MB_OK)

  我们在应用程序中可以象使用ASSERT语句一样使用它 在错误发生时 它会弹出一个对话框 其标题和内容告诉了我们错误发生的文件和代码行号 方便我们的调试 这对于不能使用ASSERT语句的项目来说是非常有用的

  除了这两个宏以外 还有记录编译时间的__TIME__ 记录日期的__DATE__ 以及记录文件修改时间的__TIMESTAMP__宏

  使用这些预定义的宏 我们几乎可以生成和VC能够生成的一样完整的源代码信息报表

  结论

cha138/Article/program/net/201311/13360

相关参考

知识大全 vc.net中实现启动画面淡入淡出

  找了半天没找实现启动画面来个淡入淡出的代码只好自己写了个呵呵还不错拿给大家看看  #undefWINVER//取消原有版本定义重新定义版本  #defineWINVERx//为了使AnimateW

知识大全 vc.net中实现启动画面来个淡入淡出

  找了半天没找实现启动画面来个淡入淡出的代码只好自己写了个呵呵还不错拿给大家看看  #undefWINVER//取消原有版本定义重新定义版本  #defineWINVERx//为了使AnimateW

异VC钠废水处理方法

江西某食品厂目前主要以生产异VC钠食品添加剂为主,生产过程中产生浓度高、色度高及可生化性强的废水。针对该公司废水的特点,采用UASB—生物接触氧化池—Biofor(一段式生物过滤氧化反应器)工艺处理废

异VC钠废水处理方法

江西某食品厂目前主要以生产异VC钠食品添加剂为主,生产过程中产生浓度高、色度高及可生化性强的废水。针对该公司废水的特点,采用UASB—生物接触氧化池—Biofor(一段式生物过滤氧化反应器)工艺处理废

异VC钠废水处理方法

江西某食品厂目前主要以生产异VC钠食品添加剂为主,生产过程中产生浓度高、色度高及可生化性强的废水。针对该公司废水的特点,采用UASB—生物接触氧化池—Biofor(一段式生物过滤氧化反应器)工艺处理废

知识大全 ASP.NET入门教程 12.3.1 处理指令

ASP.NET入门教程12.3.1处理指令  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

事故单位可不待调度指令自行先处理后报告事故有哪些?

  遇到下列事故情况时事故单位可不待调度指令自行先处理后再报告:  (1)对人身和设备有威胁时,根据现场规程采取措施。  (2)发电厂、变电站的自用电全部或部分停电时,用其他电源恢复自用电。  (3)

事故单位可不待调度指令自行先处理后报告事故有哪些?

  遇到下列事故情况时事故单位可不待调度指令自行先处理后再报告:  (1)对人身和设备有威胁时,根据现场规程采取措施。  (2)发电厂、变电站的自用电全部或部分停电时,用其他电源恢复自用电。  (3)

知识大全 C#必备知识之预编译指令

C#必备知识之预编译指令  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  预编译又称为预处理是做些

云南白药的妙用

云南白药具有活血消肿、止血止痛的功效。主治跌打损伤、瘀血肿痛、外伤出血、吐血、衄血、咳血等。除此之外,它还有许多内服治病的妙用:心绞痛。云南白药保险子1粒,加白药0.4--0.5克,口服,每日3---