pragmacomment的使⽤pragma预处理指令详解
#pragma comment( comment-type [,"commentstring"] )
该宏放置⼀个注释到对象⽂件或者可执⾏⽂件。
comment-type是⼀个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之⼀。
commentstring是⼀个提供为comment-type提供附加信息的字符串,
Remarks:
1、compiler:放置编译器的版本或者名字到⼀个对象⽂件,该选项是被linker忽略的。
2、exestr:在以后的版本将被取消。
3、lib:放置⼀个库搜索记录到对象⽂件中,这个类型应该是和commentstring(指定你要Liner搜索的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) 来声明。
有三种导出函数或者数据的⽅法,按照建议的使⽤顺序依次为:
1. 源代码中的 __declspec(dllexport)
2. .def ⽂件中的 EXPORTS 语句
3. 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了。
#pragma 预处理指令详解
在所有的预处理指令中,#pragma 指令可能是最复杂的了,它的作⽤是设定编译器的状态或者是指⽰编译器完成⼀些特定的动作。
#pragma指令对每个编译器给出了⼀个⽅法,在保持与C和C++语⾔完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指⽰是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式⼀般为: #pragma para ;其中para为参数,下⾯来看⼀些常⽤的参数。
(1)message 参数
它能够在编译信息输出窗⼝中输出相应的信息,这对于源代码信息的控制是⾮常重要的。其使⽤⽅法为:
#pragma message("消息⽂本")
当编译器遇到这条指令时就在编译输出窗⼝中将消息⽂本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们⾃⼰有可能都会忘记有没有正确的设置这些宏,此时我们可以⽤这条指令在编译的时候就进⾏检查。假设我们希望判断⾃⼰有没有在源代码的什么地⽅定义了_X86这个宏,可以⽤下⾯的⽅法:
#ifdef _X86
#pragma message("_X86 macro activated!")
#endif
我们定义了_X86这个宏以后,应⽤程序在编译时就会在编译输出窗⼝⾥显⽰"_86 macro activated!"。我们就不会因为不记得⾃⼰定义的⼀些特定的宏⽽抓⽿挠腮了。
(2)另⼀个使⽤得⽐较多的pragma参数是code_seg
格式如:
#pragma code_seg( ["section-name" [, "section-class"] ] )
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使⽤到它。
(3)#pragma once (⽐较常⽤)
只要在头⽂件的最开始加⼊这条指令就能够保证头⽂件被编译⼀次,这条指令实际上在VC6中就已经有了,
但是考虑到兼容性并没有太多的使⽤它。
(4)#pragma hdrstop
表⽰预编译头⽂件到此为⽌,后⾯的头⽂件不进⾏预编译。BCB可以预编译头⽂件以加快链接的速度,但如果所有头⽂件都进⾏预编译⼜可能占太多磁盘空间,所以使⽤这个选项排除⼀些头⽂件。
有时单元之间有依赖关系,⽐如单元A依赖单元B,所以单元B要先于单元A编译。
你可以⽤#pragma startup指定编译优先级,如果使⽤了#pragma package(smart_init),BCB就会根据优先级的⼤⼩先后编译。
(5)#pragma resource "*.dfm"
表⽰把*.dfm⽂件中的资源加⼊⼯程。*.dfm中包括窗体外观的定义。
(6)#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(...)
该指令将⼀个注释记录放⼊⼀个对象⽂件或可执⾏⽂件中。
常⽤的lib关键字,可以帮我们连⼊⼀个库⽂件。如:
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "vfw32.lib")
#pragma comment(lib, "wsock32.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 与内存对齐问题
许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的⾸地址的值是某个数k(通常它为4或8)的倍数,这就是所谓的内存对齐,⽽这个k则被称为该数据类型的对齐模数(alignment modulus)。linux所有命令都无法使用
Win32平台下的微软C编译器(cl.exe for 80x86)在默认情况下采⽤如下的对齐规则: 任何基本数据类型T的对齐模数就是T的⼤⼩,即sizeof(T)。⽐如对于double类型(8字节),
就要求该类型数据的地址总是8的倍数,⽽char类型数据(1字节)则可以从任何⼀个地址开始。
Linux下的GCC奉⾏的是另外⼀套规则(在资料中查得,并未验证,如错误请指正): 任何2字节⼤⼩(包括单字节吗?)的数据类型(⽐如short)的对齐模数是2,⽽其它所有超过2字节的数据类型(⽐如long,double)都以4为对齐模数。
ANSI C规定⼀种结构类型的⼤⼩是它所有字段的⼤⼩以及字段之间或字段尾部的填充区⼤⼩之和。填充区就是为了使结构体字段满⾜内存对齐要求⽽额外分配给结构体的空间。那么结构体本⾝有什么对齐要求吗?有的,ANSI C标准规定结构体类型的对齐要求不能⽐它所有字段中要求最严格的那个宽松,可以更严格。
如何使⽤c/c++中的对齐选项
vc6中的编译选项有 /Zp[1|2|4|8|16] ,/Zp1表⽰以1字节边界对齐,相应的,/Zpn表⽰以n字节边界对齐。n字节边界对齐的意思是说,⼀个成员的地址必须安排在成员的尺⼨的整数倍地址上或者是n的整数倍地址上,取它们中的最⼩值。
也就是:
min ( sizeof ( member ), n)
实际上,1字节边界对齐也就表⽰了结构成员之间没有空洞。/Zpn选项是应⽤于整个⼯程的,影响所有的参与编译的结构。
要使⽤这个选项,可以在vc6中打开⼯程属性页,c/c++页,选择Code Generation分类,在Struct member alignment可以选择。
要专门针对某些结构定义使⽤对齐选项,可以使⽤#pragma pack编译指令:
(1) #pragma pack( [ n ] )
该指令指定结构和联合成员的紧凑对齐。⽽⼀个完整的转换单元的结构和联合的紧凑对齐由/Zp 选项设置。
紧凑对齐⽤pack编译指⽰在数据说明层设置。该编译指⽰在其出现后的第⼀个结构或联合说明处⽣效。
该编译指⽰对定义⽆效。
当你使⽤#pragma pack ( n ) 时, 这⾥n 为1、2、4、8 或16。
第⼀个结构成员之后的每个结构成员都被存储在更⼩的成员类型或n 字节界限内。
如果你使⽤⽆参量的#pragma pack, 结构成员被紧凑为以/Zp 指定的值。该缺省/Zp 紧凑值为/Zp8 。
(2) 编译器也⽀持以下增强型语法:
#pragma pack( [ [ { push | pop } , ] [ identifier, ] ] [ n] )
若不同的组件使⽤pack编译指⽰指定不同的紧凑对齐, 这个语法允许你把程序组件组合为⼀个单独的转换单元。
带push参量的pack编译指⽰的每次出现将当前的紧凑对齐存储到⼀个内部编译器堆栈中。
编译指⽰的参量表从左到右读取。如果你使⽤push, 则当前紧凑值被存储起来;
如果你给出⼀个n 的值, 该值将成为新的紧凑值。若你指定⼀个标识符, 即你选定⼀个名称,
则该标识符将和这个新的的紧凑值联系起来。
带⼀个pop参量的pack编译指⽰的每次出现都会检索内部编译器堆栈顶的值,并且使该值为新的紧凑对齐值。
如果你使⽤pop参量且内部编译器堆栈是空的,则紧凑值为命令⾏给定的值, 并且将产⽣⼀个警告信息。
若你使⽤pop且指定⼀个n的值, 该值将成为新的紧凑值。若你使⽤p o p 且指定⼀个标识符,
所有存储在堆栈中的值将从栈中删除, 直到到⼀个匹配的标识符, 这个与标识符相关的紧凑值也从栈中移出,
并且这个仅在标识符⼊栈之前存在的紧凑值成为新的紧凑值。如果未到匹配的标识符,
将使⽤命令⾏设置的紧凑值, 并且将产⽣⼀个⼀级警告。缺省紧凑对齐为8 。
pack编译指⽰的新的增强功能让你编写头⽂件, 确保在遇到该头⽂件的前后的
紧凑值是⼀样的。
(3) 栈内存对齐
在vc6中栈的对齐⽅式不受结构成员对齐选项的影响。它总是保持对齐,⽽且对齐在4字节边界上。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论