#pragma pack effect

佐手、 提交于 2019-11-25 22:38:59

问题


I was wondering if someone could explain to me what the #pragma pack preprocessor statement does, and more importantly, why one would want to use it.

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.


回答1:


#pragma pack instructs 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:

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:

|   1   |

| AA(1) |
| BB(1) |
| BB(2) |
| BB(3) |
| BB(4) |
| CC(1) |

And sizeof(Test) would be 1 × 6 = 6.

With #pragma pack(2), the struct above would be laid out like this:

|   1   |   2   | 

| AA(1) | pad.. |
| BB(1) | BB(2) |
| BB(3) | BB(4) |
| CC(1) | pad.. |

And sizeof(Test) would be 2 × 4 = 8.

Order of variables in struct is also important. With variables ordered like following:

struct Test
{
   char AA;
   char CC;
   int BB;
};

and with #pragma pack(2), the struct would be laid out like this:

|   1   |   2   | 

| AA(1) | CC(1) |
| BB(1) | BB(2) |
| BB(3) | BB(4) |

and sizeOf(Test) would be 3 × 2 = 6.




回答2:


#pragma is 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 pack specifically 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.




回答3:


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 a and b so that b will land at a 4-byte boundary to maximize its access speed (and that's what will typically happen by default).

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 not to 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 unusedN or ignoreN, or something on that order).




回答4:


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.

#pragma allows 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.




回答5:


A compiler may place 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.




回答6:


Compiler could align members in structures to achieve maximum performance on the certain platform. #pragma pack directive 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 1 to exclude any unwanted alignment.




回答7:


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.




回答8:


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).

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).




回答9:


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.




回答10:


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:

#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

Notice how the size of struct a is exactly what the byte count is, but struct b has padding added (see this for 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.



来源:https://stackoverflow.com/questions/3318410/pragma-pack-effect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!