在C中使用#pragma


Answers:


66

#pragma 适用于特定于机器或特定于操作系统的编译器指令,即,它告诉编译器执行某些操作,设置某些选项,执行某些操作,覆盖某些默认值等,这些指令可能适用于或可能不适用于所有机器和操作系统系统。

有关更多信息,请参见msdn


11
“这可能适用于所有机器和操作系统,也可能不适用于所有机器和操作系统。” -和同一台计算机上的不同编译器。在不同的编译器上可能意味着不同的事情。
史蒂夫·杰索普

53

#pragma 用于在C语言中执行特定于实现的事情,即在当前上下文中务实,而不是从思想上教条。

我经常使用的#pragma pack(1)那个是我试图在嵌入式解决方案上从我的内存空间中挤出更多空间的方法,这些方法的结构数组最终会导致8字节对齐。

可惜我们还没有#dogma。这应该很有趣 ;)


@ShaneMacLaughlin,是否也可以pragma(1)有效提高速度?见stackoverflow.com/questions/3318410/...
Pacerier

4
@Pacerier,通常不是。根据jalfs的评论,通常在单个操作中加载和存储在32位处理器的4字节边界或64位处理器的8字节边界对齐的数据。在较小边界上对齐的数据将需要执行多项操作来加载或存储。这比较慢。
SmacL 2015年

35

如果可能的话,我通常会尽量避免使用#pragmas,因为它们非常依赖于编译器且不可移植。如果要以可移植的方式使用它们,则必须用#if/ 包围每个编译指示#endif。GCC不鼓励使用编译指示,实际上仅支持其中一些与其他编译器兼容。GCC还有其他方式可以执行其他编译器使用的编译指示相同的操作。

例如,这是您如何确保结构在MSVC中紧密包装(即,成员之间没有填充):

#pragma pack(push, 1)
struct PackedStructure
{
  char a;
  int b;
  short c;
};
#pragma pack(pop)
// sizeof(PackedStructure) == 7

这是您在GCC中执行相同操作的方式:

struct PackedStructure __attribute__((__packed__))
{
  char a;
  int b;
  short c;
};
// sizeof(PackedStructure == 7)

GCC代码更具可移植性,因为如果您想使用非GCC编译器进行编译,则要做的就是

#define __attribute__(x)

而如果要移植MSVC代码,则必须用#if/ #endif对将每个编译指示括起来。不漂亮。


3
因此,如果我想在MSVC上编译GCC代码并需要打包结构,我该怎么做呢?
SmacL

2
对于gcc,它是 struct __attribute__((__packed__)) PackedStructure
Laurent Debricon 2010年

#pragma曾经实际上不是“依赖编译器且不可移植”的。它支持各种主流移动平台,许多不-主要平台.. en.wikipedia.org/wiki/Pragma_once#Portability
xaxxon

1
请注意,C99和C11都包含(C11)§6.10.6Pragma指令和¶1 此类实现无法识别的杂语将被忽略。即使在C90中也是如此,尽管在第6.8.6节中。(这会使GCC hack在遇到无法识别的杂项时运行,因为它很久以前曾经使用过,请参见#pragmaGCC等)
Jonathan Leffler

15

将其放在#pragma once头文件的顶部将确保该文件仅包含一次。请注意,这#pragma once不是标准的C99,但大多数现代编译器都支持。

一种替代方法是使用包含防护(例如#ifndef MY_FILE #define MY_FILE ... #endif /* MY_FILE */


7

我的感觉是#pragma一个指令,如果您希望代码是特定于位置的。例如,您希望程序计数器从写入了ISR的特定地址读取程序的情况,则可以在该位置使用#pragma vector=ADC12_VECTOR并跟随指定ISR 中断例程名称及其描述


5

最好的建议是查看编译器的文档,因为编译指示从定义上讲是特定于实现的。例如,在嵌入式项目中,我已使用它们在不同部分中定位代码和数据,或声明中断处理程序。即:

#pragma code BANK1
#pragma data BANK2

#pragma INT3 TimerHandler

3
除#pragma STDC ... pragma(在所有平台(除C99之外)均已标准化)外,所有编译指示都是特定于实现的。
乔纳森·勒夫勒

4

上面的所有答案都为您提供了很好的解释,#pragma但我想举一个小例子

我只想解释一个simple OpenMP example演示#pragma其工作用途的方法

OpenMp briefly是用于多平台共享内存并行编程的实现(那么我们可以说是machine-specificoperating-system-specific

让我们来看这个例子

#include <stdio.h>
#include <omp.h>// compile with: /openmp

int main() {
   #pragma omp parallel num_threads(4)
   {
      int i = omp_get_thread_num();
      printf_s("Hello from thread %d\n", i);
   }
}

输出是

Hello from thread 0
Hello from thread 1
Hello from thread 2
Hello from thread 3

Note that the order of output can vary on different machines.

现在让我告诉你是怎么回事#pragma...

它告诉操作系统在4个线程上运行一些代码块

这只是many many applications您可以使用的一小部分#pragma

对不起外部样品 OpenMP


3

这是一个预处理程序指令,可用于打开或关闭某些功能。

它有两种类型#pragma startup#pragma exit#pragma warn

#pragma startup 允许我们指定程序启动时调用的函数。

#pragma exit 允许我们指定程序退出时调用的函数。

#pragma warn 告诉计算机是否禁止任何警告。

#pragma可以使用许多其他样式来控制编译器。


3

#pragma startup 是一个指令,用于在主函数之前调用一个函数并在主函数之后调用另一个函数,例如

#pragma startup func1
#pragma exit func2

在这里,func1运行之前mainfunc2之后。

注意:此代码仅在Turbo-C编译器中有效。要在GCC中实现此功能,您可以声明func1func2像这样:

void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();

2

总结起来,#pragma告诉编译器做一些事情。这是我使用它的几种方法:

  • #pragma可用于忽略编译器警告。例如,要使GCC关闭隐式函数声明,可以编写:

    #pragma GCC diagnostic ignored "-Wimplicit-function-declaration"

    较旧版本的libportable做到这一点可移植

  • #pragma once,当写在头文件的顶部时,将导致所述头文件被包含一次。一旦获得支持,便libportable 检查杂物。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.