Pragma Directives

本文详细介绍了C和C++中的预处理指令(#pragma),包括其语法、常见用途及各种实用示例。文章解释了如何利用这些指令进行代码优化、资源管理以及警告信息的控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Pragma Directives
Each implementation of C and C++ supports some features unique to its host machine or operating system.

Some programs, for instance, need to exercise precise control over the memory areas where data is placed or

to control the way certain functions receive parameters.
The #pragma directives offer a way for each compiler
to offer machine- and operating-system-specific features
while retaining overall compatibility with the C and C++
languages. Pragmas are machine- or operating-system-specific by definition,
and are usually different for every compiler.

Syntax

#pragma token-string

The token-string is a series of characters that gives a specific compiler instruction and arguments,
if any.

The number sign (#) must be the first non-white-space character on the line containing the pragma;

white-space characters can separate the number sign and the word pragma.
Following #pragma, write any text that the translator can parse as preprocessing tokens.
The argument to #pragma is subject to macro expansion.

If the compiler finds a pragma it does not recognize, it issues a warning, but compilation continues.

Pragmas can be used in conditional statements, to provide new preprocessor functionality,
or to provide implementation-defined information to the compiler.
The C and C++ compilers recognize the following pragmas:

alloc_text comment init_seg1 optimize
auto_inline component inline_depth pack
bss_seg data_seg inline_recursion pointers_to_members1
check_stack function intrinsic setlocale
code_seg hdrstop message vtordisp1
const_seg include_alias once warning


This is an article from MSDN, I ever wanted to use
#pragma pack(1) //which can combine structure members to one continuous memory block
on MIPS platform using GCC, but it doesn't work.


See the compiler's document, it should be illustrated there.

Under linux env using intel-based GCC, it works. 

#pragma comment( comment-type [, commentstring] )将注释放置到生成的目标文件或者可执行文件中去。commet-type一共有5种类型。可选的参数commenstring为这5种类型中的个别类型提供额外的参数。以下我们就5种类型进行分析与介绍:
compiler:将编译器名字和版本号放如目标文件。
exestr:将commentstring放到目标文件里面。
lib:将查找库的信息放如目标文件里面。此时,必须使用commentstring参数,用于记录lib的名字,最好还包括路径。
            #pragma comment( lib, "emapi" )首先在当前目录底下查找emapi.lib,然后在lib环境变量的路径里面寻找
linker:将linker option放入目标文件里面。通过注释类型确定linker的选项,从而避免在Setting对话框里面进行设置。比如:
           #pragma comment(linker, "/include:__mySymbol")
user:将一般的注释放入到目标文件里面。
#pragma optimize( "[optimization-list]", {on | off} ):
在函数一级对进行优化。该语句必须出现在函数外面,并且只会对该声明后的第一个函数有作用。on或者off确定是否起作用。
Parameter(s)Type of optimization
aAssume no aliasing.
gEnable global optimizations.
pImprove floating-point consistency.
s or tSpecify short or fast sequences of machine code.
wAssume no aliasing across function calls.
yGenerate frame pointers on the program stack.
由于比较简单,上面的英语我就不介绍了!!!调用可以是下面的形式:#pragma optimize( "atp", on )
#pragma function( function1 [, function2, ...] )            #pragma intrinsic(
function1 [, function2, ...] )
以上两个声明确定了所选函数的调用类型。如果有一函数名出现在function的参数里面,则说明以一般函数的形式调用。如果出现在了intrinsic里面则编译器在编译的时候将函数代码转化了inline代码。
#pragma data_seg( ["section-name"[, "section-class"] ] ):
为数据指定默认的存储区。如:
#pragma data_seg( "MY_DATA" )。这句声明将使得在#pramga后申明的数据将在名为MY_DATA存储区里面进行分配。

在所有的预处理指令中,#Pragma  指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作。#pragma指令对每个编译器给出了一个方法,在保持与C和C ++语言完全兼容的情况下,给出主机或操作系统专有的特征。依据定义,编译指示是机器或操作系统专有的,且对于每个编译器都是不同的。 
其格式一般为:        #Pragma  Para 
       其中Para  为参数,下面来看一些常用的参数。 
 
       (1)message  参数。  Message  参数是我最喜欢的一个参数,它能够在编译信息输出窗 
口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: 
             #Pragma  message(“消息文本”) 
             当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
       当我们在程序中定义了许多宏来控制源代码版本的时候,我们自己有可能都会忘记有没有正确的设置这些宏,此时我们可以用这条指令在编译的时候就进行检查。假设我们希望判断自己有没有在源代码的什么地方定义了_X86这个宏可以用下面的方法 
             #ifdef  _X86 
             #Pragma  message(“_X86  macro  activated!”) 
             #endif 
             当我们定义了_X86这个宏以后,应用程序在编译时就会在编译输出窗口里显示“_ 
X86  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指令激活或终止该编译程序支持的一些编译功能。例如,对循环优化功能: 
#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 data_seg建立一个新的数据段并定义共享数据,其具体格式为:

  #pragma data_seg ("shareddata")

  HWND sharedwnd=NULL;//共享数据

  #pragma data_seg()


1,#pragma data_seg()一般用于DLL中。也就是说,在DLL中定义一个共享的,有名字的数据段。 最关键的是:这个数据段中的全局变量可以被多个进程共享。否则多个进程之间无法共享DLL中的全局变量。

2, 共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。

3。如果在一个DLL中这么写:

#pragma data_seg("MyData")

int g_Value; // Note that the global is not initialized.

#pragma data_seg()

DLL提供两个接口函数:

int GetValue()
{
    return g_Value;
}

void SetValue(int n)
{
    g_Value = n;
}

然后启动两个进程A和B,A和B都调用了这个DLL,假如A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值不一定是5,而是一个未定义的值。因为DLL中的全局数据对于每一个调用它的进程而言,是私有的,不能共享的。 假如你对g_Value进行了初始化,那么g_Value就一定会被放进MyData段中。换句话说,如果A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值就一定是5!这就实现了跨进程之间的数据通信!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值