pragma:pragma 预处理指令学习



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

message参数是我最喜欢个参数它能够在编译信息输出窗口中输出相应信息
这对于源代码信息控制是非常重要其使用思路方法为:
#pragma message(\"消息文本\")
当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来
当我们在中定义了许多宏来控制源代码版本时候我们自己有可能都会忘记有没有正确设置这些宏
此时我们可以用这条指令在编译时候就进行检查假设我们希望判断自己有没有在源代码什么地方定义了_X86这个宏,
可以用下面思路方法:
#def _X86
#pragma message(\"_X86 macro activated!\")
#end
我们定义了_X86这个宏以后应用在编译时就会在编译输出窗口里显示\"_86 macro activated!\"
我们就不会不记得自己定义些特定宏而抓耳挠腮了


(2)另个使用得比较多pragma参数是code_seg

格式如:
#pragma code_seg( [\"section-name\" [, \"section-\"] ] )
它能够设置代码存放代码段当我们开发驱动时候就会使用到它


(3)#pragma _disibledevent=> 只要在头文件最开始加入这条指令就能够保证头文件被编译这条指令实际上在VC6中就已经有了
但是考虑到兼容性并没有太多使用它


(4)#pragma hdrstop

表示预编译头文件到此为止后面头文件不进行预编译BCB可以预编译头文件以加快链接速度
但如果所有头文件都进行预编译又可能占太多磁盘空间所以使用这个选项排除些头文件
有时单元的间有依赖关系比如单元A依赖单元B所以单元B要先于单元A编译
你可以用#pragma startup指定编译优先级如果使用了#pragma package(smart_init)
BCB就会根据优先级大小先后编译


(5)#pragma resource \"*.dfm\"

表示把*.dfm文件中资源加入工程*.dfm中包括窗体
外观定义[Page]


(6)#pragma warning( disable: 4507 34; _disibledevent=> 同时这个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 )
在这段代码最后重新保存所有警告信息(包括47054706和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[Page]
insert_record(REC *r)
{ /* function body */ }
#pragma warn +100 // Turn the warning message for warning #100 back _disibledevent=>每个编译器对#pragma实现区别个编译器中有效在别编译器中几乎无效可从编译器文档中查看

补充 —— #pragma pack 和内存对齐问题


许多实际计算机系统对基本类型数据在内存中存放位置有限制它们会要求这些数据首地址值是某个数k
(通常它为4或8)倍数这就是所谓内存对齐而这个k则被称为该数据类型对齐模数(alignment modulus)

Win32平台下微软C编译器(cl.exe for 80x86)在默认情况下采用如下对齐规则:
任何基本数据类型T对齐模数就是T大小(T)比如对于double类型(8字节)
就要求该类型数据地址总是8倍数而char类型数据(1字节)则可以从任何个地址开始

Linux下GCC奉行是另外套规则(在资料中查得并未验证请指正):
任何2字节大小(包括单字节吗?)数据类型(比如)对齐模数是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 ( ( 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[Page]
个结构成员的后每个结构成员都被存储在更小成员类型或n 字节界限内
如果你使用无参量#pragma pack, 结构成员被紧凑为以/Zp 指定该缺省/Zp 紧凑值为/Zp8


(2) 编译器也支持以下增强型语法:
#pragma pack( [ [ { push | pop } , ] [ identier, ] ] [ n] )

若区别组件使用pack编译指示指定区别紧凑对齐, 这个语法允许你把组件组合为个单独转换单元
带push参量pack编译指示每次出现将当前紧凑对齐存储到个内部编译器堆栈中
编译指示参量表从左到右读取如果你使用push, 则当前紧凑值被存储起来;
如果你给出个n 值, 该值将成为新紧凑值若你指定个标识符, 即你选定个名称,
则该标识符将和这个新紧凑值联系起来

个pop参量pack编译指示每次出现都会检索内部编译器堆栈顶值,并且使该值为新紧凑对齐值


如果你使用pop参量且内部编译器堆栈是空,则紧凑值为命令行给定值, 并且将产生个警告信息
若你使用pop且指定个n值, 该值将成为新紧凑值若你使用p o p 且指定个标识符,
所有存储在堆栈中值将从栈中删除, 直到找到个匹配标识符, 这个和标识符相关紧凑值也从栈中移出,
并且这个仅在标识符入栈的前存在紧凑值成为新紧凑值如果未找到匹配标识符,
将使用命令行设置紧凑值, 并且将产生级警告缺省紧凑对齐为8

pack编译指示增强功能让你编写头文件, 确保在遇到该头文件前后
紧凑值是


(3) 栈内存对齐

在vc6中栈对齐方式不受结构成员对齐选项影响它总是保持对齐而且对齐在4字节边界上

Tags:  pragmapack pragmacomment pragmaonce pragma

延伸阅读

最新评论

发表评论