6
\$\begingroup\$

I have recently come across this #pragma pack(1) preprocessor directive and was wondering why it is being used?

I Googled the usage, and found it has other options such as push,pop etc. Has anyone used this on their embedded application?

I would like to know some examples of how/why you have used this directive and on what kind of processor? What are the pro's/con's of using this directive?

Thanks.

\$\endgroup\$
1
  • \$\begingroup\$ Just something to keep in mind: pragmas are by definition non-standard and the available pragmas and their usage differ based on what compiler you're using. Lessons learned for this particular application will NOT necessarily transfer to another situation. \$\endgroup\$
    – AngryEE
    Mar 17, 2011 at 0:34

3 Answers 3

8
\$\begingroup\$

#pragma pack(1) ensures that C struct items are packed in order and on byte boundaries. It may save RAM - which is often precious in a microcontroller.

Packed structs also allow for casting directly over memory buffers for data interchange:

void f(void *buf)
{
  struct ip_header *hdr = (struct ip_header *)buf;
  hdr->dst = 0x8000001;
}

Be careful where you use #pragma pack. It's globally scoped (as it's in the preprocessor), so forgetting to turn it off will affect any #include files. If you only mean to pack certain structs, consider using GCC's __attribute__ ((packed)).

However, due to alignment issues, packed structs can impact performance. For example:

When packed into bytes:

struct
{
  uint8_t  a;
  uint32_t b;
  uint8_t  c;
  uint8_t  d:
};

Will be stored as (not accounting for endianness):

a, b0, b1, b2, b3, c, d

However, many architectures require 32bit accesses to be aligned to 32bit addresses. With the packed struct, the machine will have to make several byte accesses then stich them together again.

Faced with the above struct without packing enabled, the compiler could reorganise it as:

b0, b1, b2, b3, a, c, d

\$\endgroup\$
4
  • 4
    \$\begingroup\$ In your last example, without packing enabled and a default 32-bit alignment, some compilers might instead add extra bytes to the structure, so that it would appear in memory as a, x, x, x, b0, b1, b2, b3, c, x, x, x, d where x is a padding byte. Other variations are possible. \$\endgroup\$
    – tcrosley
    Mar 16, 2011 at 0:04
  • \$\begingroup\$ Thank you for your explanation Joby and tcrosley. I finally get it! \$\endgroup\$ Mar 16, 2011 at 0:47
  • \$\begingroup\$ It's critical you turn it off by setting it to 0 after you're done. Not doing so will result in strange behavior. \$\endgroup\$ Dec 4, 2012 at 21:37
  • 1
    \$\begingroup\$ Compilers aren't allowed to rearrange the order of fields in C structs. You could rearrange to put b first yourself. \$\endgroup\$ Apr 11, 2016 at 15:47
5
\$\begingroup\$

Another reason to pack structures on byte boundaries is to ensure the alignment of the members when transferring data between different processors.

I often need to transfer data structures between an MCU and a host PC application. The PC will pack structures on 32bit boundaries unless instructed to pack them on 1 byte boundaries. A PIC24F MCU will pack structures on 16bit boundaries unless instructed to pack them on 1 byte boundaries.

By instructing them both to pack their structures on 1 byte boundaries, it ensures the data is in the same place when accessing it on either end. Without it, you would need to pad the structures with reserve bytes so the data members would align properly.

\$\endgroup\$
0
4
\$\begingroup\$

The traditional use where I've seen this being used is for reading information from files. For example, you can define a struct whose members match those of a BMP file header, and then read all of the header in one swift read operation. OK, so BMP might not be the best example (its header does not have alignment issues on 32-bit systems), but you get the idea. I suppose this is just as useful in the embedded world.

\$\endgroup\$
2
  • \$\begingroup\$ Indeed. You can overlay a struct onto an incoming packet (or use it to construct an outgoing one), onto a set of memory-mapped registers, or build log packet, all cases where the packing could potentially differ from the CPU's optimal alignment for memory accesses. \$\endgroup\$
    – JRobert
    Mar 16, 2011 at 12:41
  • \$\begingroup\$ Quite right, but beware of endianness. When multi-byte entities are mapped onto a struct, they may need endian swapping. For example, IP packets are packed big endian, but x86 and (usually) ARM are little endian \$\endgroup\$ Mar 18, 2011 at 15:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.