#pragmacomment的使⽤⽅法pragma预处理指令详解
表⽰链接这个库。和在⼯程设置⾥写上链⼊的效果⼀样(两种⽅式等价,或说⼀个隐式⼀个显式调
⽤),不过这种⽅法写的程序别⼈在使⽤你的代码的时候就不⽤再设置⼯程ttings了。告诉连接器连接的时候要找
ws2_,这样你就不⽤在linker的lib设置⾥指定这个lib了。
⽐如:
就不需要在projecttting⾥⾯设置了
#pragmacomment(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。
[cpp]
#pragmacomment(lib,"")
[cpp]
#include"Mwic_32.h"
#pragmacomment(lib,"Mwic_")
DATA关键字指定导出项为数据项。客户程序中的数据项必须⽤extern__declspec(dllimport)来声明。
有三种导出函数或者数据的⽅法,按照建议的使⽤顺序依次为:
1.源代码中的__declspec(dllexport)
2..def⽂件中的EXPORTS语句
命令中的/EXPORT规范
所有这三种⽅法可以⽤在同⼀个程序中。LINK在⽣成包含导出的程序时还创建导⼊库,除⾮⽣成中使⽤了.exp⽂件。
LINK使⽤标识符的修饰形式。编译器在创建.obj⽂件时修饰标识符。如果entryname以其未修饰的形式指定给链接器(与其在源代码中
⼀样),则LINK将试图匹配该名称。如果⽆法找到唯⼀的匹配名称,则LINK发出错误信息。当需要将标识符指定给链接器时,请使⽤
Dumpbin⼯具获取该标识符的修饰名形式。
(3)/INCLUDE:symbol
/INCLUDE选项通知链接器将指定的符号添加到符号表。
若要指定多个符号,请在符号名称之间键⼊逗号(,)、分号(;)或空格。在命令⾏上,对每个符号指定⼀次/INCLUDE:symbol。
链接器通过将包含符号定义的对象添加到程序来解析symbol。该功能对于添包含不会链接到程序的库对象⾮常有⽤。⽤该选项指定符号将
通过/OPT:REF重写该符号的移除。
#pragma预处理指令详解
在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作⽤是设定编译器的状态或者是指⽰编译器完成⼀些特定的动作。
#pragma指令对每个编译器给出了⼀个⽅法,在保持与C和C++语⾔完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指⽰
是机器或操作系统专有的,且对于每个编译器都是不同的。
其格式⼀般为:#pragmapara;其中para为参数,下⾯来看⼀些常⽤的参数。
(1)message参数
它能够在编译信息输出窗⼝中输出相应的信息,这对于源代码信息的控制是⾮常重要的。其使⽤⽅法为:
#pragmamessage("消息⽂本")
当编译器遇到这条指令时就在编译输出窗⼝中将消息⽂本打印出来。
当我们在程序中定义了许多宏来控制源代码版本的时候,我们⾃⼰有可能都会忘记有没有正确的设置这些宏,此时我们可以⽤这条指令在
编译的时候就进⾏检查。假设我们希望判断⾃⼰有没有在源代码的什么地⽅定义了_X86这个宏,可以⽤下⾯的⽅法:
#ifdef_X86
#pragmamessage("_X86macroactivated!")
#endif
我们定义了_X86这个宏以后,应⽤程序在编译时就会在编译输出窗⼝⾥显⽰"_86macroactivated!"。我们就不会因为不记得⾃⼰定
义的⼀些特定的宏⽽抓⽿挠腮了。
(2)另⼀个使⽤得⽐较多的pragma参数是code_g
格式如:
#pragmacode_g(["ction-name"[,"ction-class"]])
它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使⽤到它。
(3)#pragmaonce(⽐较常⽤)
只要在头⽂件的最开始加⼊这条指令就能够保证头⽂件被编译⼀次,这条指令实际上在VC6中就已经有了,
但是考虑到兼容性并没有太多的使⽤它。
(4)#pragmahdrstop
表⽰预编译头⽂件到此为⽌,后⾯的头⽂件不进⾏预编译。BCB可以预编译头⽂件以加快链接的速度,但如果所有头⽂件都进⾏预编译
⼜可能占太多磁盘空间,所以使⽤这个选项排除⼀些头⽂件。
有时单元之间有依赖关系,⽐如单元A依赖单元B,所以单元B要先于单元A编译。
你可以⽤#pragmastartup指定编译优先级,如果使⽤了#pragmapackage(smart_init),BCB就会根据优先级的⼤⼩先后编译。
(5)#pragmaresource"*.dfm"
表⽰把*.dfm⽂件中的资源加⼊⼯程。*.dfm中包括窗体外观的定义。
(6)#pragmawarning(disable:450734;once:4385;error:164)
等价于:
#pragmawarning(disable:450734)//不显⽰4507和34号警告信息
#pragmawarning(once:4385)//4385号警告信息仅报告⼀次
#pragmawarning(error:164)//把164号警告信息作为⼀个错误。
同时这个pragmawarning也⽀持如下格式:
#pragmawarning(push[,n])
#pragmawarning(pop)
这⾥n代表⼀个警告等级(1---4)。
#pragmawarning(push)保存所有警告信息的现有的警告状态。
#pragmawarning(push,n)保存所有警告信息的现有的警告状态,并且把全局警告等级设定为n。
#pragmawarning(pop)向栈中弹出最后⼀个警告信息,在⼊栈和出栈之间所作的⼀切改动取消。例如:
#pragmawarning(push)
#pragmawarning(disable:4705)
#pragmawarning(disable:4706)
#pragmawarning(disable:4707)
//.......
#pragmawarning(pop)
在这段代码的最后,重新保存所有的警告信息(包括4705,4706和4707)。
(7)#pragmacomment(...)
该指令将⼀个注释记录放⼊⼀个对象⽂件或可执⾏⽂件中。
常⽤的lib关键字,可以帮我们连⼊⼀个库⽂件。如:
#pragmacomment(lib,"")
#pragmacomment(lib,"")
#pragmacomment(lib,"")
每个编译程序可以⽤#pragma指令激活或终⽌该编译程序⽀持的⼀些编译功能。
例如,对循环优化功能:
#pragmaloop_opt(on)//激活
#pragmaloop_opt(off)//终⽌
有时,程序中会有些函数会使编译器发出你熟知⽽想忽略的警告,
如“Parameterxxxisneverudinfunctionxxx”,可以这样:
#pragmawarn—100//Turnoffthewarningmessageforwarning#100
intinrt_record(REC*r)
{/*functionbody*/}
#pragmawarn+100//Turnthewarningmessageforwarning#100backon
函数会产⽣⼀条有唯⼀特征码100的警告信息,如此可暂时终⽌该警告。
每个编译器对#pragma的实现不同,在⼀个编译器中有效在别的编译器中⼏乎⽆效。可从编译器的⽂档中查看。
补充——#pragmapack与内存对齐问题
许多实际的计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的⾸地址的值是某个数k(通常它为4或8)的倍
数,这就是所谓的内存对齐,⽽这个k则被称为该数据类型的对齐模数(alignmentmodulus)。
Win32平台下的微软C编译器(80x86)在默认情况下采⽤如下的对齐规则:任何基本数据类型T的对齐模数就是T的⼤⼩,即
sizeof(T)。⽐如对于double类型(8字节),
就要求该类型数据的地址总是8的倍数,⽽char类型数据(1字节)则可以从任何⼀个地址开始。
Linux下的GCC奉⾏的是另外⼀套规则(在资料中查得,并未验证,如错误请指正):任何2字节⼤⼩(包括单字节吗?)的数据类型(⽐如
short)的对齐模数是2,⽽其它所有超过2字节的数据类型(⽐如long,double)都以4为对齐模数。
ANSIC规定⼀种结构类型的⼤⼩是它所有字段的⼤⼩以及字段之间或字段尾部的填充区⼤⼩之和。填充区就是为了使结构体字段满⾜内
存对齐要求⽽额外分配给结构体的空间。那么结构体本⾝有什么对齐要求吗?有的,ANSIC标准规定结构体类型的对齐要求不能⽐它所有
字段中要求最严格的那个宽松,可以更严格。
如何使⽤c/c++中的对齐选项
vc6中的编译选项有/Zp[1|2|4|8|16],/Zp1表⽰以1字节边界对齐,相应的,/Zpn表⽰以n字节边界对齐。n字节边界对齐的意思是
说,⼀个成员的地址必须安排在成员的尺⼨的整数倍地址上或者是n的整数倍地址上,取它们中的最⼩值。
也就是:
min(sizeof(member),n)
实际上,1字节边界对齐也就表⽰了结构成员之间没有空洞。/Zpn选项是应⽤于整个⼯程的,影响所有的参与编译的结构。
要使⽤这个选项,可以在vc6中打开⼯程属性页,c/c++页,选择CodeGeneration分类,在Structmemberalignment可以选择。
要专门针对某些结构定义使⽤对齐选项,可以使⽤#pragmapack编译指令:
(1)#pragmapack([n])
该指令指定结构和联合成员的紧凑对齐。⽽⼀个完整的转换单元的结构和联合的紧凑对齐由/Zp选项设置。
紧凑对齐⽤pack编译指⽰在数据说明层设置。该编译指⽰在其出现后的第⼀个结构或联合说明处⽣效。
该编译指⽰对定义⽆效。
当你使⽤#pragmapack(n)时,这⾥n为1、2、4、8或16。
第⼀个结构成员之后的每个结构成员都被存储在更⼩的成员类型或n字节界限内。
如果你使⽤⽆参量的#pragmapack,结构成员被紧凑为以/Zp指定的值。该缺省/Zp紧凑值为/Zp8。
(2)编译器也⽀持以下增强型语法:
#pragmapack([[{push|pop},][identifier,]][n])
若不同的组件使⽤pack编译指⽰指定不同的紧凑对齐,这个语法允许你把程序组件组合为⼀个单独的转换单元。
带push参量的pack编译指⽰的每次出现将当前的紧凑对齐存储到⼀个内部编译器堆栈中。
编译指⽰的参量表从左到右读取。如果你使⽤push,则当前紧凑值被存储起来;
如果你给出⼀个n的值,该值将成为新的紧凑值。若你指定⼀个标识符,即你选定⼀个名称,
则该标识符将和这个新的的紧凑值联系起来。
带⼀个pop参量的pack编译指⽰的每次出现都会检索内部编译器堆栈顶的值,并且使该值为新的紧凑对齐值。
如果你使⽤pop参量且内部编译器堆栈是空的,则紧凑值为命令⾏给定的值,并且将产⽣⼀个警告信息。
若你使⽤pop且指定⼀个n的值,该值将成为新的紧凑值。若你使⽤pop且指定⼀个标识符,
所有存储在堆栈中的值将从栈中删除,直到找到⼀个匹配的标识符,这个与标识符相关的紧凑值也从栈中移出,
并且这个仅在标识符⼊栈之前存在的紧凑值成为新的紧凑值。如果未找到匹配的标识符,
将使⽤命令⾏设置的紧凑值,并且将产⽣⼀个⼀级警告。缺省紧凑对齐为8。
pack编译指⽰的新的增强功能让你编写头⽂件,确保在遇到该头⽂件的前后的
紧凑值是⼀样的。
(3)栈内存对齐
在vc6中栈的对齐⽅式不受结构成员对齐选项的影响。它总是保持对齐,⽽且对齐在4字节边界上。
附加:
中有⼀条#pragmacomment(lib,""),其中和处于同⼀个名为common的⽂件
夹。
⽽⼯程⽂件在其他⽂件夹,编译的时候,编译器从⼯程⽂件的同级⽬录查找,结果当然是找不到了。
⾸先,由于这个common⽂件夹中的⽂件是所有⼈共享的,并不是每⼀个⼈的common绝对路径都相同,所以不能使⽤绝对
路径链接lib。
另外,由于多个项⽬使⽤这个common⽂件夹,但是它们的位置也各不相同,所以也不能使⽤相对于⼯程⽬录的相对路径。
但是⾄少和是处于同⼀个⽬录的,那么有办法让它⾃动找到吗?
找到最佳解决⽅法了:
还是不变,不⽤改名,然后
#defineLIBPATH(p,f)p##f
#pragmacomment(lib,LIBPATH(__FILE__,".."))
直接搞定,就算这个⽂件夹不存在也没有关系。
本文发布于:2022-12-09 19:33:03,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/88/74484.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |