I have a predefined struct (actually several) where variables span across 32-bit word boundary. In Linux (and Windows using GCC) I am able to get my structs to pack to the correct size using 'attribute((packed))'. However I cannot get it to work the same way using VC++ and #pragma pack.
Using GCC this returns a correct size of 6 bytes:
struct
{
unsigned int a : 3;
unsigned int b : 1;
unsigned int c : 15;
unsigned int troubleMaker : 16;
unsigned short padding : 13;
} __attribute__((packed)) s;
Using VC++ this returns an incorrect size of 8 bytes
#pragma pack(push)
#pragma pack(1)
struct
{
unsigned int a : 3;
unsigned int b : 1;
unsigned int c : 15;
unsigned int troubleMaker : 16;
unsigned short padding : 13;
} s;
#pragma pack(pop)
I can get things to work by splitting 'troubleMaker' across the boundary manually but I'd prefer not to. Any ideas?
Data structure alignment is the way data is arranged and accessed in computer memory. Data alignment and Data structure padding are two different issues but are related to each other and together known as Data Structure alignment.
In Structure, sometimes the size of the structure is more than the size of all structures members because of structure padding. Note: But what actual size of all structure member is 13 Bytes. So here total 3 bytes are wasted. So, to avoid structure padding we can use pragma pack as well as an attribute.
General Byte Alignment Rules Structures between 1 and 4 bytes of data should be padded so that the total structure is 4 bytes. Structures between 5 and 8 bytes of data should be padded so that the total structure is 8 bytes.
structure AThe compiler will insert a padding byte after the char to ensure short int will have an address multiple of 2 (i.e. 2 byte aligned). The total size of structa_t will be sizeof(char) + 1 (padding) + sizeof(short), 1 + 1 + 2 = 4 bytes.
I would suggest not using vendor-specific C language extensions to match device or network bit formats. Even if you get the fields to line up using a series of one-per-vendor language extensions, you still have byte order to worry about, and you still have a struct layout that requires extra instructions to access.
You can write a C99 conforming program that will work on any architecture or host and at maximum speed and cache efficiency by using the standardized C API string and memory copy functions and the Posix hton and ntoh functions.
A good practice is to use the following functions for which there exist published standards:
C99: memcpy(), Posix: htonl(), htons(), ntohl(), ntohs()
Update: here is some code that should work the same everywhere. You may need to get <stdint.h>
from this project if Microsoft still hasn't implemented it for C99, or just make the usual assumptions about int sizes.
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
struct packed_with_bit_fields { // ONLY FOR COMPARISON
unsigned int a : 3;
unsigned int b : 1;
unsigned int c : 15;
unsigned int troubleMaker : 16;
unsigned short padding : 13;
} __attribute__((packed)); // USED ONLY TO COMPARE IMPLEMENTATIONS
struct unpacked { // THIS IS THE EXAMPLE STRUCT
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t troubleMaker;
}; // NOTE NOT PACKED
struct unpacked su;
struct packed_with_bit_fields sp;
char *bits = "Lorem ipsum dolor";
int main(int ac, char **av) {
uint32_t x; // byte order issues ignored in both cases
// This should work with any environment and compiler
memcpy(&x, bits, 4);
su.a = x & 7;
su.b = x >> 3 & 1;
su.c = x >> 4 & 0x7fff;
memcpy(&x, bits + 2, 4);
su.troubleMaker = x >> 3 & 0xffff;
// This section works only with gcc
memcpy(&sp, bits, 6);
printf( sp.a == su.a
&& sp.b == su.b
&& sp.c == su.c
&& sp.troubleMaker == su.troubleMaker
? "conforming and gcc implementations match\n" : "huh?\n");
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With