1. 4FIPS
  2. PHOTOS
  3. VIDEOS
  4. APPS
  5. CODE
  6. FORUMS
  7. ABOUT
/*
(c) 2013 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=1077
*/

#include <stdio.h>
#include <stdint.h>

#define FS_PADDING_INSERT(name_, size_) uint8_t name_[size_];
#define FS_PADDING_SKIP(name_, size_)

#define FS_PACK_PUSH_1 __pragma(pack(push, 1))
#define FS_PACK_PUSH_4 __pragma(pack(push, 4))
#define FS_PACK_PUSH_8 __pragma(pack(push, 8))
#define FS_PACK_PUSH_SKIP
#define FS_PACK_POP __pragma(pack(pop))
#define FS_PACK_POP_SKIP

#define FS_DEFINE_POD(type_, declaration_)                                                              \
declaration_(type_, ,         FS_PADDING_INSERT, FS_PACK_PUSH_SKIP, FS_PACK_POP_SKIP);                  \
declaration_(type_, _PACK_0,  FS_PADDING_SKIP,   FS_PACK_PUSH_SKIP, FS_PACK_POP_SKIP);                  \
declaration_(type_, _PACK_1,  FS_PADDING_INSERT, FS_PACK_PUSH_1,    FS_PACK_POP);                       \
declaration_(type_, _PACK_4,  FS_PADDING_INSERT, FS_PACK_PUSH_4,    FS_PACK_POP);                       \
declaration_(type_, _PACK_8,  FS_PADDING_INSERT, FS_PACK_PUSH_8,    FS_PACK_POP);                       \
static_assert(sizeof(type_) == sizeof(type_##_PACK_0), "sizeof("#type_") != sizeof("#type_"_PACK_0)");  \
static_assert(sizeof(type_) == sizeof(type_##_PACK_1), "sizeof("#type_") != sizeof("#type_"_PACK_1)");  \
static_assert(sizeof(type_) == sizeof(type_##_PACK_4), "sizeof("#type_") != sizeof("#type_"_PACK_4)");  \
static_assert(sizeof(type_) == sizeof(type_##_PACK_8), "sizeof("#type_") != sizeof("#type_"_PACK_8)");

// struct Foo
#define FS_DECLARE_FOO(type_, tag_, padding_, pack_push_, pack_pop_)    \
pack_push_                                                              \
struct type_##tag_                                                      \
{                                                                       \
    uint8_t a;                                                          \
    uint8_t b;                                                          \
    uint8_t c;                                                          \
    padding_(_reserved0, 1);                                            \
    uint32_t x;                                                         \
};                                                                      \
pack_pop_
FS_DEFINE_POD(Foo, FS_DECLARE_FOO);
#undef FS_DECLARE_FOO

// struct Bar
#define FS_DECLARE_BAR(type_, tag_, padding_, pack_push_, pack_pop_)    \
pack_push_                                                              \
struct type_##tag_                                                      \
{                                                                       \
    uint16_t num_foos;                                                  \
    padding_(_reserved0, 2);                                            \
    Foo##tag_ foos[1];                                                  \
};                                                                      \
pack_pop_
FS_DEFINE_POD(Bar, FS_DECLARE_BAR);
#undef FS_DECLARE_BAR

int main()
{
    printf("*** Foo ***\n");
    printf("Manual packing:  %u bytes\n", sizeof(Foo));
    printf("Default packing: %u bytes\n", sizeof(Foo_PACK_0));
    printf("Tight packing:   %u bytes\n", sizeof(Foo_PACK_1));
    printf("32-bit packing:  %u bytes\n", sizeof(Foo_PACK_4));
    printf("64-bit packing:  %u bytes\n", sizeof(Foo_PACK_8));

    printf("\n*** Bar ***\n");
    printf("Manual packing:  %u bytes\n", sizeof(Bar));
    printf("Default packing: %u bytes\n", sizeof(Bar_PACK_0));
    printf("Tight packing:   %u bytes\n", sizeof(Bar_PACK_1));
    printf("32-bit packing:  %u bytes\n", sizeof(Bar_PACK_4));
    printf("64-bit packing:  %u bytes\n", sizeof(Bar_PACK_8));

    return 0;
}

// Compiled under Visual C++ 2012 (x64), output:
// *** Foo ***
// Manual packing:  8 bytes
// Default packing: 8 bytes
// Tight packing:   8 bytes
// 32-bit packing:  8 bytes
// 64-bit packing:  8 bytes
//
// *** Bar ***
// Manual packing:  12 bytes
// Default packing: 12 bytes
// Tight packing:   12 bytes
// 32-bit packing:  12 bytes
// 64-bit packing:  12 bytes