【C/C++】详解 您所在的位置:网站首页 114514的含义出处详解 【C/C++】详解

【C/C++】详解

2024-07-16 11:48| 来源: 网络整理| 查看: 265

文章目录 § - 1 前言§ - 2 简介§ - 3 基本语法一、message参数二、once参数三、hdrstop参数四、code_seg参数五、warning参数六、pack参数八、intrinsic参数七、function参数八、init_seg参数九、inline_depth参数十、auto_inline参数十一、check_stack十二、const_seg参数十三、bss_seg参数十四、alloc_text参数结语

§ - 1 前言

在阅读本文前,您需要知道:

#define预处理器条件预处理器

之前在网上浏览的时候,发现全网没几篇文章能系统全面的讲解这个预处理器,我自己琢磨了一下,写了

§ - 2 简介

有一说一,所有预处理其中,#pragma应该最复杂了。

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

听着很绕对吧,我们慢慢来。

§ - 3 基本语法

#pragma的基本语法是:

#pragma PARA(...)

其中PARA是命令参数,可以是以下值(仅列出常用命令):

PARAalloc_textcommentinit_seg1optimizeauto_inlinecomponentinline_depthpackbss_segdata_seginline_recursionpointers_to_memberscheck_stackfunctionintrinsicsetlocalecode_seghdrstopmessagevtordispconst_seginclude_aliasoncewarning

以下,正文。

一、message参数

message可以在不中断编译的情况下发送 字面字符串常量 到 标准输出 。 它通常用于编译时显示一些信息。 语法如下:2

#pragma message(msg·string) //注:【msg·string】意思即参数msg需要string类型 //forC:string即char*/char[],字符串

其中,msg即发送的信息。它必须是string(即char[]、char*) 【实例】以下代码将在编译时发送 hello world到标准输出并在运行时输出HELLO WORLD!!!

#include //forC: #include #pragma message("hello world\n") int main(){ std::cout // stored in .text } //将函数存放在.my_data1节中 #pragma code_seg(".my_data1") void func2 () { // stored in my_data1 } //r1为标识符,将函数放入.my_data2节中 #pragma code_seg(push, r1, ".my_data2") void func3 () { // stored in my_data2 } /*------------------------------*/ //例如 #pragma code_seg(“PAGE”) //作用是将此部分代码放入分页内存中运行。 #pragma code_seg() //将代码段设置为默认的代码段 #pragma code_seg("INIT") //加载到INIT内存区域中,成功加载后,可以退出内存

关于分页内存,请参考分页内存与非分页内存。

五、warning参数

语法:

#pragma warning( \ warning-specifier·kyw : warning-order[list]·int \ [ \ ; \ warning-specifier·kyw : warning-order[list]·int \ [...] \ ] \ ) #pragma warning( push [, warning-lv] ) #pragma warning( pop )

参数:

w a r n i n g warning warning - s p e c i f i e r specifier specifier · 标识符,可以为: o n c e once once —— 只显示指定信息一次。 d e f a u l t default default —— 对指定信息应用默认的编译程序选项。1 | 2 | 3 | 4 —— 对指定信息引用给定的警告等级。 d i s a b l e disable disable —— 不显示指定信息。 e r r o r error error —— 将指定信息作为错误提出。 w a r n i n g warning warning - o r d e r order order · int,可以是任意警告编号。

你可以同时对多组编号操作,如下:

#pragma warning( \ disable : 4507 34; \ once : 4385; \ error : 164 \ ) /* 请注意,行末的【\】是必须的, * 如果没有它则意味着#pragma的结束,编译器无法理解后面的参数 */ //因此,除非必须,请尽量将它们写在一行

这相当于:

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

对于那些关于代码生成的,大于4699的警告标号,warning编译指示仅在函数定义外时有效。如果指定的警告编号大于4699并且用于函数内时被忽略。

【实例】- 使用warning参数禁止,再解除警告。

int a; #pragma warning( disable : 4705 ) void func(){ cout push | pop } ] [ , identifier ] ] [ n ] )

该语法允许你将使用不同紧缩编译指示的组件合并到同一个翻译单元内。 每次出现有push参数的pack编译指示将保存当前的紧缩对齐值到一个内部的编译程序堆栈。编译指示的参数列表从左向右读取。如果你使用了push,当前紧缩值被保存。如果你提供了一个n值,这个值将成为新的紧缩值。如果你指定了一个你选定的标示符,这个标示符将和新的紧缩值关联。 每次出现有pop参数的pack编译指示从内部编译程序堆栈顶部取出一个值并将那个值作为新的紧缩对齐。如果你用了pop,而内部编译程序堆栈是空的,对齐值将从命令行得到,同时给出一个警告。如果你用了pop并指定了n的值,那个值将成为新的紧缩值。如果你用了pop并指定了一个标示符,将移去所有保存在堆栈中的的值直到匹配的找到匹配的标示符,和该标示符关联的紧缩值也被从堆栈中移出来成为新的紧缩值。如果没有找到匹配的标示符,将从命令行获取紧缩值并产生一个1级警告。默认的紧缩对齐是8。

使用后者的语法允许你编写头文件保证在使用头文件之前和其后的紧缩值是一样的:

//文件:hdr.h #pragma pack(push,enter_hdr) //BODY #pragma pack(pop,enter_hdr) //结束

上述代码使得进入头文件时将当前紧缩值和标示符enter_hdr关联并推入,被记住。在头文件尾部的pack编译选项移去所有在头文件中可能遇到的紧缩值并移去和enter_hdr关联的紧缩值。这样头文件保证了在使用头文件之前和其后的紧缩值是一样的。

类似地,你可以在包含不同头文件时使用不同紧缩值(如果文件内部没有定义):

#pragma pack(push,ent_hdr_) #include"hdr.h" #pragma pack(pop,ent_hdr_)

上述代码保护了hdr.h中的紧缩值。

八、intrinsic参数

语法:

#pragma intrinsic( [ func1 [ , func2 [...] ] ] )

该预处理将参数列表中的函数名(无需带【()】)声明为内含函数(内联),见内含函数

intrinsic编译提示指定对在编译指示参数表中函数调用是内含的。 编译程序像嵌入代码一样生成内含函数,而不是函数调用。 下面列出了 具有内含形式的库函数。 一旦遇到 intrinsic 编译指示, 它从第一个包含指定内含函数的函数定义开始起作用。 作用持续到源文件尾部或者出现包含相同内含函数的 function 编译指示。

以下函数具有内含形式:

_disable_enable_inp_inpw_lrotl_lrotr_outp_outpw_rotl_rotr_strsetabsfabslabsmemcmpmemcpymemsetstrcatstrcmpstrcpystrlen---

请注意,下列浮点函数没有内含形式:( 然而它们具有直接将参数通过浮点芯片传送而不是推入程序堆栈的版本。)

acosasincoshfmodpowsinhtanh

当你同时指定/Oi 和/Og 编译程序选项(或者任何包含/Og, /Ox, /O1 和/O2 的选项) 时下列浮点函数具有真正的内含形式:

atanexplog10sqrtatan2logsintancos

你可以用编译程序选项/Op 或/Za 来覆盖真内含浮点选项的生成。 在这种情况下, 函数会像一般库函数一样被生成, 同时直接将参数通过浮点芯片传送而不是推入程序堆栈。

七、function参数

语法:

#pragma function( func1 [ , func2 [...] ] )

内含函数的执行是将函数代码嵌入调用处(并非直接调用),使用function显示地强制调用该函数。其持续作用到源文件的尾部或者出现对同一个内含函数指定intrinsic编译指示。function编译指示只能用于函数外——在全局层次。

八、init_seg参数

【注:此预编译提示仅C++特有】 语法:

#pragma init_seg( \ { \ compiler | \ lib | \ user | \ section-name·string [, func-name·string] \ } \ )

该编译提示是指定影响启动代码执行的关键字或代码段。

因为全局静态对象的初始化可以包含执行代码,所以你必须指定一个关键字来定义什么时候构造对象。在使用需要初始化的动态连接库(DLL)或程序库时使用init_seg编译指示是尤其重要的。

参数选项:

c o m p i l e r compiler compiler —— 由Microsoft C运行时间库保留。在这个组中的对象将第一个构造。 l i b lib lib —— 用于第三方类库开发者的初始化。在这个组中的对象将在标记为构造compiler的对象之后,其它对象之前构造。 u s e r user user —— 用于任何其它用户。在这个组中的对象将最后构造。 s e l e c t i o n selection selection - n a m e name name · 字符串 —— 允许显式地指定初始化段。在用户指定的section-name中的对象将不会隐式地构造,而它们的地址将会被放置在由section-name命名的段中。 f u n c func func - n a m e name name · 字符串 【可选】—— 指定当程序退出时,作为atexit函数调用的函数。这个函数必须具有和atexit函数相同的形式:(如果你需要延迟初始化,你能够选择指定显式的段名。随后你必须调用每个静态对象的构造函数。)int func_name(void (__cdecl *)(void));

九、inline_depth参数

语法:

#pragma inline_depth( dep·int【0,255】 ) //所需参数为[0,255]的整数

该编译提示通过控制能够被扩展的一系列函数调用(从0到255次)来控制嵌入函数扩展的发生次数,这个编译指示控制用inline,__inline标记的或在/Ob2选项下能自动嵌入的嵌入函数。

inline_depth编译指示控制能够被扩展的一系列函数调用。例如,如果嵌入深度是4,并且如果A调用B然后调用C,所有的3次调用都将做嵌入扩展。然而,如果设置的最近一次嵌入深度是2,则只有A和B被扩展,而C仍然作为函数调用。

为了使用这个编译指示,你必须设置编译程序选项/Ob为1或者2。用这个编译指示指定的深度设定在该指示后面的第一个函数开始生效。如果你在括号内不指定一个值,inline_depth设置嵌入深度到默认值8。

在扩展时,嵌入深度可以被减少而不能被增加。如果嵌入深度是6,同时在扩展过程中预处理程序遇到一个inline_depth编译指示设置为8,则深度保持为6。

嵌入深度0将拒绝嵌入扩展,深度255将设置在嵌入扩展时没有限制。如果用一个没有指定值的编译指示,则使用为默认值。

十、auto_inline参数

语法:

#pragma auto_inline( { on | off } )

当指定off时将任何一个可以被考虑为作为自动嵌入扩展候选的函数排除出该范围。为了使用auto_inline编译指示,将其紧接着写在一个函数定义之前或之后(不是在其内部)。该编译指示将在其出现以后的第一个函数定义开始起作用。auto_inline编译指示对显式的inline函数不起作用。

十一、check_stack

语法:

#pragma check_stack( [ { on | off } ] ) #pragma check_stack( [ { + | - } ] )

当指定为off|-时编译程序关闭堆栈探测,若是on|+则打开堆栈探测,对于未给出参数的,以默认设置决定。 如果你没有给出check­_stack编译指示的参数,堆栈检查将恢复到在命令行指定的行为:

使用/Gs编译?结果(前提是未给出参数,否则按参数)是后续的函数关闭堆栈检查否后续的函数开启堆栈检查

十二、const_seg参数

语法:

#pragma const_seg(  \ [  \ [ { push | pop}, ] \ [ identifier·idt, ]  \ ] \ [  \ segment-name·string  \ [, segment-class·string ]  \ ] \ ) 

类似于code_seg,它指定用于常量数据的默认段。

用const_seg编译指示分配的数据不包含任何关于其位置的信息。

第二个参数segment-class是用于兼容2.0版本以前的Visual C++的,现在将忽略它。

十三、bss_seg参数

语法:

#pragma bss_seg(  \ [  \ [ { push | pop}, ] \ [ identifier·idt, ]  \ ] \ [  \ segment-name·string  \ [, segment-class·string ]  \ ] \ ) 

它为未初始化数据指定缺省段。在一些情况下,你能使用bss_seg将所有未初始化数据安排在一个段中来加速你的装载时间。

用bss_seg编译指示分配的数据不包含任何关于其位置的信息。

第二个参数segment-class是用于兼容2.0版本以前的Visual C++的,现在将忽略它。

十四、alloc_text参数

语法:

#pragma alloc_text( txtforfunc·string , func1 [ , func2... ] )

命名特别定义的函数驻留的代码段。该编译指示必须出现在函数说明符和函数定义之间。(即在函数说明后,定义前) 注意:alloc_text不接受C++中方法(类成员函数)及重载函数的处理,仅能以C的方式说明(extern "C")。如果你试图将这个编译指示应用于一个具有C++连接方式的函数时,将出现一个编译程序错误。 另外,该编译提示不能用在函数内部

结语

精力有限,只能先写到这了,下期见!

@HaohaoCppDebuger |寻兰  2021/12/2 

-----THE END-----THANK YOU !

加粗 命令为仅C++,下同。 ↩︎

代码段中以//forC: ...注释的语句为C语言写法。下同。 ↩︎

代码中 [ ] 括住的部分为可选。下同。 { XX | YY } 表示XX或YY任选。下同。 语法代码段的换行实际不合法,注意行末【\】。下同。 ↩︎

该指令用来指定函数在.obj文件中存放的节,观察OBJ文件可以使用VC自带的dumpbin命令行程序,函数在.obj文件中默认的存放节为.text节,如果code_seg没有带参数的话,则函数存放在.text节中。

↩︎


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有