预处理指令中#Pragma

在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。

其格式一般为: #pragma Para。其中Para 为参数,下面来看一些常用的参数

1.message 参数

  Message 参数能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为:

  #pragma message(“消息文本”)

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

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

  #ifdef _X86

  #pragma message("_X86 macro activated!")

  #endif

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

2.code_seg

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

  #pragma code_seg( ["section-name"[,"section-class"] ] )

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

3.#pragma once

  (比较常用)

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

  #pragma once是编译相关,就是说这个编译系统上能用,但在其他编译系统不一定可以,也就是说移植性差,不过现在基本上已经是每个编译器都有这个定义了。

  #ifndef,#define,#endif这个是C++语言相关,这是C++语言中的宏定义,通过宏定义避免文件多次编译。所以在所有支持C++语言的编译器上都是有效的,如果写的程序要跨平台,最好使用这种方式

4.#pragma hdrstop

  #pragma hdrstop表示预编译头文件到此为止,后面的头文件不进行预编译。BCB可以预编译头文件以加快链接的速度,但如果所有头文件都进行预编译又可能占太多磁盘空间,所以使用这个选项排除一些头文件。

  有时单元之间有依赖关系,比如单元A依赖单元B,所以单元B要先于单元A编译。你可以用#pragma startup指定编译优先级,如果使用了#pragma package(smart_init) ,BCB就会根据优先级的大小先后编译。

5.#pragma resource

  #pragma resource "*.dfm"表示把*.dfm文件中的资源加入工程。*.dfm中包括窗体外观的定义。

6.#pragma warning

  #pragma warning( disable : 4507 34; once : 4385; error : 164 )

  等价于:

  #pragma warning(disable:4507 34) // 不显示4507和34号警告信息

  #pragma warning(once:4385) // 4385号警告信息仅报告一次

  #pragma warning(error:164) // 把164号警告信息作为一个错误。

  同时这个pragma warning 也支持如下格式:

  #pragma warning( push [ ,n ] )

  #pragma warning( pop )

  这里n代表一个警告等级(1---4)。

  #pragma warning( push )保存所有警告信息的现有的警告状态。

  #pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告等级设定为n。

  #pragma warning( pop )向栈中弹出最后一个警告信息,

  在入栈和出栈之间所作的一切改动取消。例如:

  #pragma warning( push )

  #pragma warning( disable : 4705 )

  #pragma warning( disable : 4706 )

  #pragma warning( disable : 4707 )

  //.......

  #pragma warning( pop )

  在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。

7.pragma comment

  pragma comment(...)

  该指令将一个注释记录放入一个对象文件或可执行文件中。

  常用的lib关键字,可以帮我们连入一个库文件。

  每个编译程序可以用#pragma指令激活或终止该编译程序支持的一些编译功能。例如,对循环优化功能:

  #pragma loop_opt(on) // 激活

  #pragma loop_opt(off) // 终止

  有时,程序中会有些函数会使编译器发出你熟知而想忽略的警告,如“Parameter xxx is never used in function xxx”,可以这样:

  #pragma warn —100 // Turn off the warning message for warning #100

  int insert_record(REC *r)

  { /* function body */ }

  #pragma warn +100 // Turn the warning message for warning #100 back on

  函数会产生一条有唯一特征码100的警告信息,如此可暂时终止该警告。

  每个编译器对#pragma的实现不同,在一个编译器中有效在别的编译器中几乎无效。可从编译器的文档中查看。

  #pragma pack(n)和#pragma pop()

  struct sample

  {

  char a;

  double b;

  };

  当sample结构没有加#pragma pack(n)的时候,sample按最大的成员那个对齐;

  (所谓的对齐是指对齐数为n时,对每个成员进行对齐,既如果成员a的大小小于n则将a扩大到n个大小;

  如果a的大小大于n则使用a的大小;)所以上面那个结构的大小为16字节.

  当sample结构加#pragma pack(1)的时候,sizeof(sample)=9字节;无空字节。

  (另注:当n大于sample结构的最大成员的大小时,n取最大成员的大小。

  所以当n越大时,结构的速度越快,大小越大;反之则)

  #pragma pop()就是取消#pragma pack(n)的意思了,也就是说接下来的结构不用#pragma pack(n)

  #pragma comment( comment-type ,["commentstring"] )

  comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。

  commentstring是一个提供为comment-type提供附加信息的字符串。

  注释类型:

  1、compiler:

  放置编译器的版本或者名字到一个对象文件,该选项是被linker忽略的。

  2、exestr:

  在以后的版本将被取消。

  3、lib:

  放置一个库搜索记录到对象文件中,这个类型应该是和commentstring(指定你要Linker搜索的lib的名称和路径)这个库的名字放在Object文件的默认库搜索记录的后面,linker搜索这个这个库就像你在命令行输入这个命令一样。你可以在一个源文件中设置多个库记录,它们在object文件中的顺序和在源文件中的顺序一样。如果默认库和附加库的次序是需要区别的,使用Z编译开关是防止默认库放到object模块。

  4、linker:

  指定一个连接选项,这样就不用在命令行输入或者在开发环境中设置了。

  只有下面的linker选项能被传给Linker.

  /DEFAULTLIB ,/EXPORT,/INCLUDE,/MANIFESTDEPENDENCY, /MERGE,/SECTION

  (1) /DEFAULTLIB:library

  /DEFAULTLIB 选项将一个 library 添加到 LINK 在解析引用时搜索的库列表。用 /DEFAULTLIB指定的库在命令行上指定的库之后和 .obj 文件中指定的默认库之前被搜索。忽略所有默认库 (/NODEFAULTLIB) 选项重写 /DEFAULTLIB:library。如果在两者中指定了相同的 library 名称,忽略库 (/NODEFAULTLIB:library) 选项将重写 /DEFAULTLIB:library。

  (2)/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]

  使用该选项,可以从程序导出函数,以便其他程序可以调用该函数。也可以导出数据。通常在 DLL 中定义导出。entryname是调用程序要使用的函数或数据项的名称。ordinal 在导出表中指定范围在 1 至 65,535 的索引;如果没有指定 ordinal,则 LINK 将分配一个。NONAME关键字只将函数导出为序号,没有 entryname。

  DATA 关键字指定导出项为数据项。客户程序中的数据项必须用 extern __declspec(dllimport)来声明。

  有三种导出定义的方法,按照建议的使用顺序依次为:

  源代码中的 __declspec(dllexport).def 文件中的 EXPORTS 语句LINK 命令中的 /EXPORT 规范所有这三种方法可以用在同一个程序中。LINK 在生成包含导出的程序时还创建导入库,除非生成中使用了 .exp 文件。

  LINK 使用标识符的修饰形式。编译器在创建 .obj 文件时修饰标识符。如果 entryname以其未修饰的形式指定给链接器(与其在源代码中一样),则 LINK 将试图匹配该名称。如果无法找到唯一的匹配名称,则 LINK 发出错误信息。当需要将标识符指定给链接器时,请使用 Dumpbin 工具获取该标识符的修饰名形式。

  (3)/INCLUDE:symbol

  /INCLUDE 选项通知链接器将指定的符号添加到符号表。

  若要指定多个符号,请在符号名称之间键入逗号 (,)、分号 (;) 或空格。在命令行上,对每个符号指定一次 /INCLUDE:symbol。

  链接器通过将包含符号定义的对象添加到程序来解析 symbol。该功能对于添包含不会链接到程序的库对象非常有用。用该选项指定符号将通过 /OPT:REF 重写该符号的移除。

  我们经常用到的是#pragma comment(lib,"*.lib")这类的。#pragma comment(lib,"Ws2_32.lib")表示链接Ws2_32.lib这个库。 和在工程设置里写上链入Ws2_32.lib的效果一样,不过这种方法写的 程序别人在使用你的代码的时候就不用再设置工程settings了

8.#pragma data_seg

  #pragma data_seg介绍[1]

  用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为:

  #pragma data_seg ("shareddata")

  HWND sharedwnd=NULL;//共享数据

  #pragma data_seg()

  -----------------------------------------------------------------

  1,#pragma data_seg()一般用于DLL中。也就是说,在DLL中定义一个共享的有名字的数据段。最关键的是:这个数据段中的全局变量可以被多个进程共享,否则多个进程之间无法共享DLL中的全局变量。

  2,共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。例如,

  #pragma data_seg("MyData")

  int g_Value; // Note that the global is not initialized.

  #pragma data_seg()

  DLL提供两个接口函数:

  int GetValue()

  {

  return g_Value;

  }

  void SetValue(int n)

  {

  g_Value = n;

  }

  然后启动两个进程A和B,A和B都调用了这个DLL,假如A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值不一定是5,而是一个未定义的值。因为DLL中的全局数据对于每一个调用它的进程而言,是私有的,不能共享的。假如你对g_Value进行了初始化,那么g_Value就一定会被放进MyData段中。换句话说,如果A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值就一定是5,这就实现了跨进程之间的数据通信。

本文摘自百度百科. 更详细的信息请参考:http://blog.csdn.net/wrq147/archive/2009/07/31/4398674.aspx

时间: 2024-11-05 06:09:37

预处理指令中#Pragma的相关文章

C/C++预处理指令#pragma详解

      在所有的预处理指令中,#Pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征.依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的.其格式一般为: #Pragma Para其中Para 为参数,下面来看一些常用的参数.      (1)message 参数. Message 参数是我最喜欢的一个参数,它能够在编

VC预处理指令与宏定义

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

常用C/C++预处理指令详解_C 语言

预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查.预处理命令以符号"#"开头. 常用的预处理指令包括: 宏定义:#define 文件包含:#include 条件编译:#if.#elif.#ifndef.#ifdef.#endif.#undef 错误信息指令:#error #line指令 布局控制:#pragma 宏定义 宏定义又称为宏代换.宏替换,简称"宏".宏替换只作替换,不做计算,不做表达式求解.宏定义分带参数的宏定义和不带参数的宏

C#预处理指令之#line、#pragma warning

#line #line 使您可以修改编译器的行号以及(可选)错误和警告的文件名输出.下面的示例说明如何报告与行号关联的两个警告.#line 200 指令强迫行号为 200(尽管默认值为 #7).另一行 (#9) 作为默认 #line 指令的结果跟在通常序列后. class MainClass { static void Main() { #line 200 int i; // CS0168 on line 200 #line default char c; // CS0168 on line 9

C#中的预处理指令

与C++不同,C#没有独立的预处理器.C#中的预处理指令(pre-processing directives)仅仅用来与C保持一致,而并不是编译器开始编译代码之前的一个单独的处理步骤,它是作为词法解析的一部分来执行的. 预处理指令都以#号开头并位于行首(前面可以出现空格符).在介绍条件编译之前,我们先学习两条用于定义符号和取消符号定义的预处理指令:#define和#undef. #define指令对于有一点C语言知识的读者来说再熟悉不过,它非常类似于C中的宏定义: #define COUNT 这

预处理指令

C#预处理指令基本概念 虽然同C和C++的术语"预处理指令"名称一样,但C#的其实并没有单独的预处理步骤,也就是说在VS等环境中并没有预处理的编译器. 预处理指令能够用于替换源文件中的信息.以#(Sharp)字符和预处理指令名称开头.例如: #define MAX 习惯于将预处理指令的名称全部设为大写.和C与C++不同的是,C#中的预处理指令的名称后不加数字等.C\C++所支持的宏函数在C#中也是不支持的. 还可以使用#region来设置一个区域,同时也可以通过Visual Studi

c/c++预处理指令总结

常见的预处理功能: 预处理器的主要作用就是把通过预处理的内建功能对一个资源进行等价替换,最常见的预处理有:文件包含,条件编译.布局控制和宏替换4种. 文件包含:#include 是一种最为常见的预处理,主要是做为文件的引用组合源程序正文. 条件编译:#if,#ifndef,#ifdef,#endif,#undef等也是比较常见的预处理,主要是进行编译时进行有选择的挑选,注释掉一些指定的代码,以达到版本控制.防止对文件重复包含的功能. 布局控制:#progma,这也是我们应用预处理的一个重要方面,

WCF 找不到类型“WcfServiceStudy.WcfService”,它在 ServiceHost 指令中提供为 Servi

错误信息: "/Service"应用程序中的服务器错误. 找不到类型"HC.Test.DMTools.Service.ModelToolService",它在 ServiceHost 指令中提供为 Service 特性值,或在配置元素 system.serviceModel/serviceHostingEnvironment/serviceActivations 中提供. 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以

[译]ng指令中的compile与link函数解析

通常大家在使用ng中的指令的时候,用的链接函数最多的是link属性,下面这篇文章将告诉大家complie,pre-link,post-link的用法与区别. 原文地址 angularjs里的指令非常神奇,允许你创建非常语义化以及高度重用的组件,可以理解为web components的先驱者. 网上已经有很多介绍怎么使用指令的文章以及相关书籍,相互比较的话,很少有介绍compile与link的区别,更别说pre-link与post-link了. 大部分教程只是简单的说下compile会在ng内部用