-2

I am stumped by an apparent error in my use of offsetof() within an X macro. The code below shows two examples of a rather simple structure, one defined explicitly, and another defined using an X macro. The offsets of each structure field within both structures are then printed to the screen. As you can see in comments below, the c field in the structure defined with X macro shows an incorrect offset.

I believe this is a print problem. Can someone please shed some light on this mystery?

#include <stdio.h>
#include <stdlib.h>

const char fmt[] = "%-5s 0x%04x(%05d)\n";

#define i(s, f) \
    #f, \
    offsetof(s, f), \
    offsetof(s, f)

int main(void)
{
    /**********************************
    METHOD1 - CORRECTLY PRINTS

        a     0x0000(00000)
        b     0x0004(00004)
        c     0x0008(00008)
        d     0x0030(00048)

    **********************************/
    typedef struct {
        uint32_t a;
        uint32_t b;
        uint32_t c[10];
        uint32_t d;
    } struct1;

    printf(fmt, i(struct1, a));
    printf(fmt, i(struct1, b));
    printf(fmt, i(struct1, c));
    printf(fmt, i(struct1, d));

    printf("\n");

    /**********************************
    METHOD2 - PRINTS WRONG INFO

        a     0x0000(00000)
        b     0x0004(00004)
        c[10] 0x0030(00048)  <== WRONG
        d     0x0030(00048)

    **********************************/

    #define FIELDS \
        X(uint32_t, a,     "") \
        X(uint32_t, b,     "") \
        X(uint32_t, c[10], "") \
        X(uint32_t, d,     "") \

    typedef struct {
    #define X(type, name, descr) type name;
        FIELDS
    #undef X
    } struct2;

    #define X(type, name, descr) printf(fmt, i(struct2, name));
        FIELDS
    #undef X

    return 0;
}
Paul Grinberg
  • 1,184
  • 14
  • 37
  • You use the wrong format specifier, causing undefined behaviour. `%x` is for unsigned int, and `%d` is for `int`, but `offsetof` yields a `size_t`. – M.M Jul 20 '17 at 03:00
  • Your X-macro ends up outputting `offsetof(struct2, c[10])`, which is different to the first example which did `offsetof(struct1, c)` – M.M Jul 20 '17 at 03:03
  • Thank you @M.M for the clarification of where the problem occurs. Can you think of a way to redefine my x-macro to produce the desired result? – Paul Grinberg Jul 20 '17 at 03:13
  • Maybe you could make the X macro have the declaration and the plain name separately , e.g. `X(uint32_t c[10], c, "")` – M.M Jul 20 '17 at 03:15
  • @rici Yes, I stand corrected. Will remove the comment. – Ajay Brahmakshatriya Jul 20 '17 at 04:40

2 Answers2

3

In the second X macro:

  #define X(type, name, descr) printf(fmt, i(struct2, name));
  FIELDS

This expands to:

printf(fmt, "a", offsetof(struct2, a), offsetof(struct2, a));
printf(fmt, "b", offsetof(struct2, b), offsetof(struct2, b));
printf(fmt, "c[10]", offsetof(struct2, c[10]), offsetof(struct2, c[10]));
printf(fmt, "d", offsetof(struct2, d), offsetof(struct2, d));

offsetof(struct2, c[10]) is obviously not the same as offsetof(struct2, c).

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
-1

With the help of above comments, I came up with the answer. For structure elements that are arrays, I need to have a different X-macro definition.

#include <stdio.h>
#include <stdlib.h>

const char fmt[] = "%-5s 0x%04x(%05d)\n";

#define i(s, f) \
    #f, \
    offsetof(s, f), \
    offsetof(s, f)

int main(void)
{
    /**********************************
       METHOD1 - CORRECTLY PRINTS

           a     0x0000(00000)
           b     0x0004(00004)
           c     0x0008(00008)
           d     0x0030(00048)

     **********************************/
    typedef struct {
        uint32_t a;
        uint32_t b;
        uint32_t c[10];
        uint32_t d;
    } struct1;

    printf(fmt, i(struct1, a));
    printf(fmt, i(struct1, b));
    printf(fmt, i(struct1, c));
    printf(fmt, i(struct1, d));

    printf("\n");

    /**********************************
       METHOD2 - PRINTS WRONG INFO

           a     0x0000(00000)
           b     0x0004(00004)
           c     0x0008(00008) <== CORRECT
           d     0x0030(00048)

     **********************************/

    #define FIELDS \
         X(uint32_t, a,     "") \
         X(uint32_t, b,     "") \
        AX(uint32_t, c, 10, "") \
         X(uint32_t, d,     "") \

    typedef struct {
    #define  X(type, name, descr)       type name;
    #define AX(type, name, size, descr) type name[size];
        FIELDS
    #undef  X
    #undef AX
    } struct2;

    #define  X(type, name, descr)       printf(fmt, i(struct2, name));
    #define AX(type, name, size, descr) printf(fmt, i(struct2, name));
        FIELDS
    #undef  X
    #undef AX

    return 0;
}
Paul Grinberg
  • 1,184
  • 14
  • 37