I am facing a strange issue when using #pragma pack
.
I have the following structs:
st_a
: packed with#pragma pack(1)
. Size = 1 byte. Contains bitfields.st_b
: packed with#pragma pack(2)
. Size = 14 bytes.st_c
: packed with#pragma pack(2)
. Size = 16 bytes. Containsst_a
andst_b
st_d
: packed with#pragma pack(2)
. Size = 16 bytes. Containsst_a
and contents ofst_b
(st_b
's members)
So, since st_a
is of 1 byte packed under #pragma pack(1)
, and since it's inside st_c
which is packed under #pragma pack(2)
, there should be one extra byte of padding in st_c
immediately after st_a
and that extra byte should be followed by contents of st_b
which is a character buffer of even length (10).
But, this thing works strangely when I take the contents of st_b
out and put them directly in st_a
. The padding is seen after the character buffer, rather than before (See output below).
Can somebody explain, why this strange behavior occurs?
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#pragma pack(push)
#pragma pack(1)
typedef struct A {
int a : 1;
int b : 1;
int c : 1;
int d : 1;
int e : 1;
int f : 1;
int g : 1;
int h : 1;
} st_a;
#pragma pack(pop)
#pragma pack(push)
#pragma pack(2)
typedef struct B {
unsigned char buf[10];
int x;
} st_b;
typedef struct C {
st_a temp1;
st_b temp2;
} st_c;
typedef struct D {
st_a temp3;
unsigned char buf1[10];
int x1;
} st_d;
#pragma pack(pop)
void print_hex(unsigned char* packet) {
for (int i = 0; i < 16; i++) {
printf("%x ", packet[i]);
} printf("\n");
}
int main() {
st_c one;
one.temp1.a = 0;
one.temp1.b = 0;
one.temp1.c = 1;
one.temp1.d = 0;
one.temp1.e = 0;
one.temp1.f = 0;
one.temp1.g = 0;
one.temp1.h = 0;
memcpy(&one.temp2.buf, "ABCDEFGHIJ", 10);
one.temp2.x = 10;
st_d two;
two.temp3.a = 0;
two.temp3.b = 0;
two.temp3.c = 1;
two.temp3.d = 0;
two.temp3.e = 0;
two.temp3.f = 0;
two.temp3.g = 0;
two.temp3.h = 0;
memcpy(&two.buf1, "ABCDEFGHIJ", 10);
two.x1 = 10;
print_hex((unsigned char*) &one);
print_hex((unsigned char*) &two);
cout << sizeof(st_c) << " " << sizeof(st_a) << " " << sizeof(st_b) << " " << sizeof(st_d) << endl;
return 0;
}
Output:
4 5b 41 42 43 44 45 46 47 48 49 4a a 0 0 0
4 41 42 43 44 45 46 47 48 49 4a 0 a 0 0 0
16 1 14 16
Note: I am using GCC version 4.4.x.
Some notes about the output:
In first line, 5b
is the padding byte introduced between 4
which is 1 byte st_a
and 41
which is the first character of buffer of st_b
.
In second line, 0
is the padding byte introduced between 4a
which is last character of buffer and a
which is the integer following the character buffer in st_d
.
Third line prints the size of all the structures.
You are not detecting the padding correctly. Are you expecting the padding to be zero bytes? There is no reason to expect that. The value in the padding bytes can be anything. The zeroes you are seeing at the end are part of the 4 bytes of
st_b.x1
. It's value is 10 which as a little endian 2's complement integer with be stored as0A 00 00 00
A better way to look at the padding is to use the
offsetof
macro. For example:This outputs:
which clearly shows there is a single padding byte between
p1
andp2
.Another way to see the padding as zeroes would be to zeroize all the bytes of the struct right after it's declaration:
Then the output of you program would look like: