C语言 #pragma 包效果
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3318410/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
#pragma pack effect
提问by Cenoc
I was wondering if someone could explain to me what the #pragma packpreprocessor statement does, and more importantly, why one would want to use it.
我想知道是否有人可以向我解释#pragma pack预处理器语句的作用,更重要的是,为什么要使用它。
I checked out the MSDN page, which offered some insight, but I was hoping to hear more from people with experience. I've seen it in code before, though I can't seem to find where anymore.
我查看了MSDN 页面,该页面提供了一些见解,但我希望从有经验的人那里听到更多。我以前在代码中见过它,但我似乎再也找不到在哪里了。
回答by Nick Meyer
#pragma packinstructs the compiler to pack structure members with particular alignment. Most compilers, when you declare a struct, will insert padding between members to ensure that they are aligned to appropriate addresses in memory (usually a multiple of the type's size). This avoids the performance penalty (or outright error) on some architectures associated with accessing variables that are not aligned properly. For example, given 4-byte integers and the following struct:
#pragma pack指示编译器以特定对齐方式打包结构成员。大多数编译器,当你声明一个结构体时,会在成员之间插入填充以确保它们与内存中的适当地址对齐(通常是类型大小的倍数)。这避免了与访问未正确对齐的变量相关的某些体系结构上的性能损失(或完全错误)。例如,给定 4 字节整数和以下结构:
struct Test
{
char AA;
int BB;
char CC;
};
The compiler could choose to lay the struct out in memory like this:
编译器可以选择将结构放在内存中,如下所示:
| 1 | 2 | 3 | 4 |
| AA(1) | pad.................. |
| BB(1) | BB(2) | BB(3) | BB(4) |
| CC(1) | pad.................. |
and sizeof(Test)would be 4 × 3 = 12, even though it only contains 6 bytes of data. The most common use case for the #pragma(to my knowledge) is when working with hardware devices where you need to ensure that the compiler does not insert padding into the data and each member follows the previous one. With #pragma pack(1), the struct above would be laid out like this:
并且sizeof(Test)将是 4 × 3 = 12,即使它只包含 6 个字节的数据。#pragma(据我所知)最常见的用例是在使用硬件设备时,您需要确保编译器不会将填充插入数据并且每个成员都遵循前一个。使用#pragma pack(1),上面的结构将如下所示:
| 1 |
| AA(1) |
| BB(1) |
| BB(2) |
| BB(3) |
| BB(4) |
| CC(1) |
And sizeof(Test)would be 1 × 6 = 6.
并且sizeof(Test)将是 1 × 6 = 6。
With #pragma pack(2), the struct above would be laid out like this:
使用#pragma pack(2),上面的结构将如下所示:
| 1 | 2 |
| AA(1) | pad.. |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
| CC(1) | pad.. |
And sizeof(Test)would be 2 × 4 = 8.
并且sizeof(Test)将是 2 × 4 = 8。
Order of variables in struct is also important. With variables ordered like following:
struct 中变量的顺序也很重要。变量排序如下:
struct Test
{
char AA;
char CC;
int BB;
};
and with #pragma pack(2), the struct would be laid out like this:
和#pragma pack(2),结构将这样布置:
| 1 | 2 |
| AA(1) | CC(1) |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
and sizeOf(Test)would be 3 × 2 = 6.
并且sizeOf(Test)将是 3 × 2 = 6。
回答by nmichaels
#pragmais used to send non-portable (as in this compiler only) messages to the compiler. Things like disabling certain warnings and packing structs are common reasons. Disabling specific warnings is particularly useful if you compile with the warnings as errors flag turned on.
#pragma用于向编译器发送不可移植的(仅在此编译器中)消息。禁用某些警告和打包结构之类的事情是常见的原因。如果在错误标志打开时使用警告进行编译,则禁用特定警告特别有用。
#pragma packspecifically is used to indicate that the struct being packed should not have its members aligned. It's useful when you have a memory mapped interface to a piece of hardware and need to be able to control exactly where the different struct members point. It is notably not a good speed optimization, since most machines are much faster at dealing with aligned data.
#pragma pack特别用于指示被打包的结构不应使其成员对齐。当您有一个硬件的内存映射接口并且需要能够准确控制不同结构成员指向的位置时,它很有用。这显然不是一个好的速度优化,因为大多数机器在处理对齐数据时要快得多。
回答by Jerry Coffin
It tells the compiler the boundary to align objects in a structure to. For example, if I have something like:
它告诉编译器将结构中的对象对齐到的边界。例如,如果我有类似的东西:
struct foo {
char a;
int b;
};
With a typical 32-bit machine, you'd normally "want" to have 3 bytes of padding between aand bso that bwill land at a 4-byte boundary to maximize its access speed (and that's what will typically happen by default).
对于典型的 32 位机器,您通常“希望”在a和之间有 3 个字节的填充,b以便b将其置于 4 个字节的边界以最大化其访问速度(这就是默认情况下通常会发生的情况)。
If, however, you have to match an externally defined structure you want to ensure the compiler lays out your structure exactly according to that external definition. In this case, you can give the compiler a #pragma pack(1)to tell it notto insert any padding between members -- if the definition of the structure includes padding between members, you insert it explicitly (e.g., typically with members named unusedNor ignoreN, or something on that order).
但是,如果您必须匹配外部定义的结构,您希望确保编译器完全根据该外部定义布置您的结构。在这种情况下,你可以给编译器#pragma pack(1)来告诉它不插入成员之间的任何填充-如果结构的定义包括成员之间的填充,可以插入它明确(例如,通常命名为会员unusedN或ignoreN,或东西上命令)。
回答by Pontus Gagge
Data elements (e.g. members of classes and structs) are typically aligned on WORD or DWORD boundaries for current generation processors in order to improve access times. Retrieving a DWORD at an address which isn't divisible by 4 requires at least one extra CPU cycle on a 32 bit processor. So, if you have e.g. three char members char a, b, c;, they actually tend to take 6 or 12 bytes of storage.
数据元素(例如类和结构的成员)通常在当前一代处理器的 WORD 或 DWORD 边界上对齐,以缩短访问时间。在不能被 4 整除的地址处检索 DWORD 需要在 32 位处理器上至少增加一个 CPU 周期。因此,如果您有例如三个 char 成员char a, b, c;,它们实际上往往会占用 6 或 12 个字节的存储空间。
#pragmaallows you to override this to achieve more efficient space usage, at the expense of access speed, or for consistency of stored data between different compiler targets. I had a lot of fun with this transitioning from 16 bit to 32 bit code; I expect porting to 64 bit code will cause the same kinds of headaches for some code.
#pragma允许您覆盖它以实现更有效的空间使用,代价是访问速度,或不同编译器目标之间存储数据的一致性。从 16 位代码到 32 位代码的转换给我带来了很多乐趣;我希望移植到 64 位代码会对某些代码造成同样的麻烦。
回答by Clifford
A compiler mayplace structure members on particular byte boundaries for reasons of performance on a particular architecture. This may leave unused padding between members. Structure packing forces members to be contiguous.
出于特定体系结构上的性能原因,编译器可以将结构成员放置在特定字节边界上。这可能会在成员之间留下未使用的填充。结构填充强制成员是连续的。
This may be important for example if you require a structure to conform to a particular file or communications format where the data you need the data to be at specific positions within a sequence. However such usage does not deal with endian-ness issues, so although used, it may not be portable.
这可能很重要,例如,如果您需要一个结构符合特定文件或通信格式,其中您需要数据位于序列中的特定位置。然而,这种用法不处理字节序问题,所以虽然使用了它,但它可能无法移植。
It may also to exactly overlay the internal register structure of some I/O device such as a UART or USB controller for example, in order that register access be through a structure rather than direct addresses.
它也可以精确地覆盖一些 I/O 设备(例如 UART 或 USB 控制器)的内部寄存器结构,以便通过结构而不是直接地址访问寄存器。
回答by Kirill V. Lyadvinsky
Compiler could align members in structures to achieve maximum performance on the certain platform. #pragma packdirective allows you to control that alignment. Usually you should leave it by default for optimum performance. If you need to pass a structure to the remote machine you generally will use #pragma pack 1to exclude any unwanted alignment.
编译器可以对齐结构中的成员以在特定平台上实现最大性能。#pragma pack指令允许您控制该对齐方式。通常您应该默认保留它以获得最佳性能。如果您需要将结构传递给远程机器,您通常会使用它#pragma pack 1来排除任何不需要的对齐。
回答by Kirill V. Lyadvinsky
I've used it in code before, though only to interface with legacy code. This was a Mac OS X Cocoa application that needed to load preference files from an earlier, Carbon version (which was itself backwards-compatible with the original M68k System 6.5 version...you get the idea). The preference files in the original version were a binary dump of a configuration structure, that used the #pragma pack(1)to avoid taking up extra space and saving junk (i.e. the padding bytes that would otherwise be in the structure).
我以前在代码中使用过它,但只是为了与遗留代码交互。这是一个 Mac OS X Cocoa 应用程序,需要从早期的 Carbon 版本(它本身向后兼容原始 M68k System 6.5 版本......你懂的)加载首选项文件。原始版本中的首选项文件是配置结构的二进制转储,它使用#pragma pack(1)来避免占用额外空间并节省垃圾(即,否则将在结构中的填充字节)。
The original authors of the code had also used #pragma pack(1)to store structures that were used as messages in inter-process communication. I think the reason here was to avoid the possibility of unknown or changed padding sizes, as the code sometimes looked at a specific portion of the message struct by counting a number of bytes in from the start (ewww).
代码的原始作者还用于#pragma pack(1)存储在进程间通信中用作消息的结构。我认为这里的原因是为了避免出现未知或更改填充大小的可能性,因为代码有时会通过从头开始计算字节数(ewww)来查看消息结构的特定部分。
回答by stonemetal
I have seen people use it to make sure that a structure takes a whole cache line to prevent false sharing in a multithreaded context. If you are going to have a large number of objects that are going to be loosely packed by default it could save memory and improve cache performance to pack them tighter, though unaligned memory access will usually slow things down so there might be a downside.
我见过人们使用它来确保结构采用整个缓存行以防止多线程上下文中的错误共享。如果您将拥有大量默认松散打包的对象,则可以节省内存并提高缓存性能以将它们打包得更紧,但未对齐的内存访问通常会减慢速度,因此可能存在缺点。
回答by msw
You'd likely only want to use this if you were coding to some hardware (e.g. a memory mapped device) which had strict requirements for register ordering and alignment.
如果您正在对某些对寄存器排序和对齐有严格要求的硬件(例如内存映射设备)进行编码,您可能只想使用它。
However, this looks like a pretty blunt tool to achieve that end. A better approach would be to code a mini-driver in assembler and give it a C calling interface rather than fumbling around with this pragma.
然而,这看起来是实现这一目标的一个非常生硬的工具。更好的方法是在汇编程序中编写一个微型驱动程序并为其提供 C 调用接口,而不是摸索这个 pragma。
回答by wangchow
Note that there are other ways of achieving data consistency that #pragma pack offers (for instance some people use #pragma pack(1) for structures that should be sent across the network). For instance, see the following code and its subsequent output:
请注意,#pragma pack 提供了其他实现数据一致性的方法(例如,有些人使用 #pragma pack(1) 来表示应该通过网络发送的结构)。例如,请参阅以下代码及其后续输出:
#include <stdio.h>
struct a {
char one;
char two[2];
char eight[8];
char four[4];
};
struct b {
char one;
short two;
long int eight;
int four;
};
int main(int argc, char** argv) {
struct a twoa[2] = {};
struct b twob[2] = {};
printf("sizeof(struct a): %i, sizeof(struct b): %i\n", sizeof(struct a), sizeof(struct b));
printf("sizeof(twoa): %i, sizeof(twob): %i\n", sizeof(twoa), sizeof(twob));
}
The output is as follows: sizeof(struct a): 15, sizeof(struct b): 24 sizeof(twoa): 30, sizeof(twob): 48
输出如下: sizeof(struct a): 15, sizeof(struct b): 24 sizeof(twoa): 30, sizeof(twob): 48
Notice how the size of struct a is exactly what the byte count is, but struct b has padding added (see thisfor details on the padding). By doing this as opposed to the #pragma pack you can have control of converting the "wire format" into the appropriate types. For instance, "char two[2]" into a "short int" et cetera.
请注意一个结构的大小是如何准确的字节数是什么,但结构B已经添加填充(见本关于填充细节)。通过这样做而不是#pragma 包,您可以控制将“有线格式”转换为适当的类型。例如,将“char two[2]”转换为“short int”等等。

