#pragma的常用方法讲解


#### 2.2 #pragma message(messageString)


**不中断编译的情况下,发送一个字符串文字量到标准输出**。message编译指示的典型运用是在编译时显示信息,例如:



#if _M_IX86 >= 500 //查看定义的宏有没有大于500,或者有时用作检查有没有定义宏
#pragma message(“_M_IX86 >= 500”)
#endif


**messagestring 参数可以是扩展到字符串的宏**,您可以通过任意组合将此类宏与字符串串联起来,例如:



#pragma message( "Compiling " FILE ) //显示被编译的文件
#pragma message( "Last modified on " TIMESTAMP ) //文件最后一次修改的日期和时间


**如果在 message 杂注中使用预定义的宏,则该宏应返回字符串,否则必须将该宏的输出转换为字符串**,例如:



#define STRING2(x) #x
#define STRING(x) STRING2(x)

#pragma message (FILE “[” STRING(LINE) “]: test”) //注意把行号转成了字符串


#### 2.3、#pragma waring(…)


启用编译器警告消息的行为和选择性修改,语法为:



#pragma warning( warning-specifier : warning-number-list [,warning-specifier : warning-number-list…] )

#pragma warning( push[ , n ] )
#pragma warning( pop )


warning-specifier能够是下列值之一:


![在这里插入图片描述](https://img-blog.csdnimg.cn/20181125201427138.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTY0MDI5OA==,size_16,color_FFFFFF,t_70)  
 估计看这个表会头晕,我来举几个例子:



#pragma warning( disable : 4507 34; once : 4385; error : 164 ) //这1行跟下面3行效果一样

#pragma warning( disable : 4507 34 ) //不发出4507和34警告,即有4507和34警告时不显示
#pragma warning( once : 4385 ) //4385警告信息只报告一次
#pragma warning( error : 164 ) //把164警告信息作为一个错误


注意:**对于范围 4700-4999 内的警告编号**(与代码生成相关联),在编译器遇到函数的左大括号时生效的警告状态将对函数的其余部分生效。 在函数中使用 warning 杂注更改编号大于 4699 的警告的状态只会在函数末尾之后生效。 以下示例演示如何正确放置 warning 杂注来禁用代码生成警告消息然后还原该消息



#pragma warning(disable:4700) //不发生4700警告
void Test() //这里之前的状态管用,若把上面一行移动到函数里面,则照常发生警告
{
int x;
int y = x; //没有C4700的警告
#pragma warning(default:4700) //4700的警告恢复到默认值
}

int main()
{
int x;
int y = x; //发生C4700的警告
}


下面来看warning推送和弹出的用法,语法为:



#pragma warning( push [ ,``n ] )
#pragma warning( pop )


其中 n 表示警告等级(1 到 4)。


warning( push )指令存储每个警告的当前警告状态。  
 warning( push, n)指令存储每个警告的当前状态并将全局警告级别设置为 n。  
 warning( pop )指令 弹出推送到堆栈上的最后一个警告状态。  
 **在 push 和 pop 之间对警告状态所做的任何更改都将被撤消**。



#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
// Some code //代码的书写,这里不会发出4705、4706、4707的警告
#pragma warning( pop ) //会将每个警告(包括4705、4706、4707)的状态还原为代码开始的状态


当你编写头文件时,你能用push和pop来保证任何用户修改的警告状态不会影响正常编译你的头文件。在头文件开始的地方使用push,在结束地方使用pop。例如,假定你有一个不能顺利在4级警告下编译的头文件,下面的代码改变警告等级到3,然后在头文件的结束时恢复到原来的警告等级。



#pragma warning( push, 3 )
// Declarations/ definitions //要书写的代码
#pragma warning( pop )


#### 2.4、#pragma comment(comment-type [,“commentstring”])


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


comment-type 是一个预定义的标识符(如下所述,一共5个),它指定了注释记录的类型。 可选 commentstring 是一个字符串,它提供了某些注释类型的附加信息。 由于 commentstring 是一个字符串,因此它遵循有关转义字符、嵌入的引号 (") 和串联的字符串的所有规则。


**compiler**  
 将编译器的名称和版本号置于对象文件中。 此注释记录将被链接器忽略。 如果为此记录类型提供 commentstring 参数,则编译器会生成警告。


**exestr**  
 将 commentstring 置于对象文件中。 在链接时,会将该字符串置于可执行文件内。 加载可执行文件时,不会将字符串加载到内存中;但是,可以使用在文件中查找可打印字符串的程序来找到它。 此注释记录类型的一个用途是将版本号或类似信息嵌入可执行文件中。


**lib(这个最常用了)**  
 将库搜索记录置于对象文件中。 此注释类型必须带有包含您希望链接器搜索的库的名称(和可能的路径)的 commentstring 参数。 库名称遵循对象文件中的默认库搜索记录;链接器会搜索此库,这就像在命令行上对其命名一样,前提是未使用 /nodefaultlib 指定库。 可以将多个库搜索记录置于同一个源文件中;各个记录将以其在源文件中显示的顺序出现在对象文件中。


如果默认库和添加的库的顺序很重要,则使用 /Zl 开关进行编译会阻止将默认库名称置于对象模块中。 然后,可使用另一个注释指令在添加的库的后面插入默认库的名称。 与这些指令一起列出的库将以其在源代码中的发现顺序出现在对象模块中。



#pragma comment(lib, “comctl32.lib”)
#pragma comment( lib, “mysql.lib” )


**linker**  
 将链接器选项置于对象文件中。 可以使用注释类型来指定链接器选项,而不是将其传递到命令行或在开发环境中指定它。 例如,可以指定 /include 选项来强制包含符号:



#pragma comment(linker, “/include:__mySymbol”)


**user**  
 将一般注释置于对象文件中。 commentstring 参数包含注释文本。 此注释记录将被链接器忽略。


#### 2.5、#pragma region … /endregion …


#pragma region是Visual C++中特有的预处理指令。它可以让你折叠特定的代码块,从而使界面更加清洁,便于编辑其他代码。折叠后的代码块不会影响编译。你也可以随时展开代码块以进行编辑等操作



int main()
{

#pragma region demo_region //这里前面会有折叠符,折叠时提示 demo_region所写内容
int a = 10;
int b = 20;
int c = ADD( a + b );
#pragma endregion demo_region //需要跟#pragma region配套使用

}


折叠代码块的方法:如同Visual C++中折叠函数、类、命名空间,当代码被包含在如上所述的指令之间后,#pragma region这一行的左边会出现一个“-”号,单击以折叠内容,同时“-”号会变成“+”号,再次单击可以展开代码块


#### 2.6、#pragma alias(…)


指定 short\_filename 将用作 long\_filename 的别名,语法为:



#pragma include_alias( "long_filename ", “short_filename” )
#pragma include_alias( <long_filename>, <short_filename> )


某些文件系统允许长度超过 8.3 FAT 文件系统限制的头文件名。 因为较长的头文件名的前八个字符可能不是唯一的,因此编译器无法简单地将较长的名称截断为 8.3。 每当编译器遇到 long\_filename 字符串时,都将替换 short\_filename,并改为查找头文件 short\_filename。 此杂注必须在相应的 #include 指令之前出现。


要搜索的别名**必须完全符合规范**,**无论是大小写、拼写还是双引号或尖括号的使用**。 include\_alias 杂注对文件名执行简单的字符串匹配;将不执行任何其他文件名验证。 例如:



#pragma include_alias(“mymath.h”, “math.h”) //要在头文件引用之前定义

#include “./mymath.h” //多了"./",必须完全匹配
#include “sys/mymath.h” //多了"sys/ "


您可以使用 include\_alias 杂注将任何头文件名映射到另一个头文件名。 例如



#pragma include_alias( “api.h”, “c:\version1.0\api.h” )
#pragma include_alias( <stdio.h>, <newstdio.h> )
#include “api.h”
#include <stdio.h>


不要将用双引号括起来的文件名与用尖括号括起的文件名组合在一起。 例如,给定上述两个 #pragma include\_alias 指令,编译器将不对下列 #include 指令执行任何替换:



#include <api.h>
#include “stdio.h”


#### 2.7#pragma pack([ show ] | [ push | pop ] [, identifier ] , n)


**指定结构、联合和类成员的封装对齐。其实就是改变编译器的内存对齐方式**。这个功能对于集合数据体使用,默认的数据的对齐方式占用内存比较大,可进行修改。


在没有参数的情况下调用pack会将n设置为编译器选项/zp中设置的值。**如果未设置编译器选项,windows默认为8,linux默认为4**。


具体的使用方法为,其中n的取值必须是2的幂次方,即1、2、4、8、16等:



  1. #pragma pack(show) 以警告信息的形式显示当前字节对齐的值.

  2. #pragma pack(n) 将当前字节对齐值设为 n .

  3. #pragma pack() 将当前字节对齐值设为默认值(通常是8) .

  4. #pragma pack(push) 将当前字节对齐值压入编译栈栈顶.

  5. #pragma pack(pop) 将编译栈栈顶的字节对齐值弹出并设为当前值.

  6. #pragma pack(push, n) 先将当前字节对齐值压入编译栈栈顶, 然后再将 n 设为当前值.

  7. #pragma pack(pop, n) 将编译栈栈顶的字节对齐值弹出, 然后丢弃, 再将 n 设为当前值.

  8. #pragma pack(push, identifier) 将当前字节对齐值压入编译栈栈顶, 然后将栈中保存该值的位置标识为 identifier .

  9. #pragma pack(pop, identifier) 将编译栈栈中标识为 identifier 位置的值弹出, 并将其设为当前值. 注意, 如果栈中所标识的位置之上还有值, 那会先被弹出并丢弃.

  10. #pragma pack(push, identifier, n) 将当前字节对齐值压入编译栈栈顶, 然后将栈中保存该值的位置标识为 identifier, 再将 n 设为当前值.

  11. #pragma pack(pop, identifier, n) 将编译栈栈中标识为 identifier 位置的值弹出, 然后丢弃, 再将 n 设为当前值. 注意, 如果栈中所标识的位置之上还有值, 那会先被弹出并丢弃.

注意: 如果在栈中没有找到 pop 中的标识符, 则编译器忽略该指令, 而且不会弹出任何值.


使用时最好是成对出现的,要不容易引起错误,设置之后记得用完给恢复,如:



#pragma pack(n) //设置以n个字节为对齐长度
struct
{
int ia;
char cb;
}
#pragma pack () //弹出n个字节对齐长度,设置默认值为对齐长度


**如果想给单独一个结构体设置对齐长度还可以使用C++ 11 标准中的alignas。**


但是不是设置#pragma pack(n)就按照设置的字节进行对齐呢?其实并不是这样的,实际的对齐字节数要符合以下规则:  
 **1、若设置了对齐长度n,实际对齐长度=Min(设置字节长度,结构体成员的最宽字节数)。若没有设置n,实际对齐长度 = Min(结构体成员的最宽字节数,默认对齐长度)。  
 2、每个成员相对于首地址的偏移量(offset)都是实际对齐长度的整数倍,若不满足编译器进行填充。  
 3、数据集合的总大小为实际对齐长度的整数倍,若不是编译器进行填充。**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值