Structure Packing

Programs in this toolkit make extensive use of packed data structures to simplify source code and guarantee reliability; however, this creates portability issues because different compilers implement structure packing in different ways. Three common structure packing mechanisms are:

_packed

The __packed keyword is not part of any C or C++ standard but it is recognized by some compilers, such as the ARM C/C++ and OpenBSD C compiler. This keyword only affects the data structure that it prefaces and it is an ideal way to selectively pack structures. It can be easily defined and undefined using a preprocessor macro. Atheros has elected to insert this keyword wherever it might be appropriate. The ARM C compilers accept this keyword.

Example 3.5.  Packing Structures with keyword __packed

typedef struct __packed header_eth 
{ 
	uint8_t source [ETHER_ADDR_LEN]; 
	uint8_t target [ETHER_ADDR_LEN]; 
	uint16_t protocol; 
} 
header_eth; 

__attribute__ ((packed))

Attributes are not part of any C or C++ standard but they are recognized by the gcc and Sun Microsystems C compiler. Attributes only affect structures and functions that reference them in their declaration. This is convenient because we can use a preprocessor macro to define the keyword __packed, mentioned above, to be __attribute__ ((packed)). Atheros includes this definition in tools/types.h and OpenBSD does this in their system header files.

Example 3.6.  Packing Structures with Attribute packed

typedef struct __attribute__ ((packed)) header_eth 
{ 
	uint8_t source [ETHER_ADDR_LEN]; 
	uint8_t target [ETHER_ADDR_LEN]; 
	uint16_t protocol; 
} 
header_eth; 

#pragrma pack

Pragmas are part of most C and C++ language standards but some compilers do not recognize or implement the pack pragma. In addition, different compilers implement it in different ways. The pack pragma affects all data structures up the next pack pragma or end of compile unit. Most pragma implementations accept the push and pop option for pragma nesting. Some pragma pack implementations accept no arguments, most permit either one or two arguments while others allow three arguments. OpenBSD does not recognize this pragma and generates warnings in all cases. Aside from all that, the pack pragma is the most widely supported method for declaring packed structures.

Example 3.7.  Packing Structures with the Pragma pack

#pragma pack (push, 1) 
struct header_eth 
{ 
	uint8_t source [ETHER_ADDR_LEN]; 
	uint8_t target [ETHER_ADDR_LEN]; 
	uint16_t protocol; 
} 
header_eth; 
#pragma pack (pop)

The Atheros Way

Toolkit programs declares packed structures using all three methods, as shown below.

Example 3.8.  Packing Structures the Atheros Way

#ifndef __packed 
#ifdef __GNUC__ 
#define __packed __attribute__ ((packed)) 
#else 
#define __packed 
#endif 
#endif 

#ifndef __GNUC__
#pragma pack (push, 1)
#endif
 
struct __packed header_eth 
{ 
	uint8_t source [ETHER_ADDR_LEN]; 
	uint8_t target [ETHER_ADDR_LEN]; 
	uint16_t protocol; 
} 
header_eth; 

#ifndef __GNUC__
#pragma pack (pop)
#endif