Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get struct field name by offset C [closed]

Tags:

c

I am not sure it is possible, but I am trying to find a way to get the struct's field name by its offset.

Assume I have a simple struct, and macro that uses these fields by name:

#define COPY_FIELD(target, source, field) \
    do { \
        (target) = source.field; \
    } while (0)

struct fields {
  int a;
  int b;
  int c;
};

Assuming I can't change the macro, Is there a way to use it relative to the beginning of the struct:
Or any other way that will not require me to write the field's name?
Regular usage example:

int return_target() {
    struct fields f;
    int target;
    f.a = 0;
    f.b = 1;
    f.c = 2;
    COPY_FIELD(target, f, c);
    return target;
}

What I need (something like that):

int return_target(int idx) {
    struct fields f;
    int target;
    COPY_FIELD(target, f, (a + idx));
    return target;
}

Of course, the last code will not work because the source.(a+idx) is not defined.
Any ideas?

like image 410
ItamarG Avatar asked May 04 '26 18:05

ItamarG


1 Answers

There is no way to compute the field name by its offset, but you can use a switch statement to emulate the desired behavior:

int return_target(int idx) {
    struct fields f = { 1, 2, 3 };
    int target = -1;
    switch (idx) {
    case 0: COPY_FIELD(target, f, a); break;
    case 1: COPY_FIELD(target, f, b); break;
    case 2: COPY_FIELD(target, f, c); break;
    }
    return target;
}

Abusing the rules, you could pretend the structure is an array of int, and write this:

int return_target(int idx) {
    struct fields f = { 1, 2, 3 };
    int target;
    COPY_FIELD(target, f, a * 0 + idx[(int *)&f]);
    return target;
}

COPY_FIELD(target, f, a * 0 + idx[(int *)&f]); expands to

do { (target) = source.a * 0 + idx[(int *)&f]; } while (0)

which sets target to the value of int located idx places from the beginning of the structure. This only works because all of the fields have the same type int. Note also that the code will have undefined behavior if idx is not 0, 1 or 2.

Here is a cleaner way to do it using an array of offsets:

#include <stddef.h>  // for the offsetof macro

struct fields {
  int a;
  int b;
  int c;
};

static size_t field_offsets[] = {
    offsetof(struct fields, a),
    offsetof(struct fields, b),
    offsetof(struct fields, c),
};

int return_target(int idx) {
    struct fields f = { 1, 2, 3 };
    if (idx >= 0 && idx < sizeof(field_offsets) / sizeof(*field_offsets)) {
        return *(int *)((char *)&f + field_offsets[idx]);
    } else {
        // invalid index
        return -1;
    }
}
like image 74
chqrlie Avatar answered May 07 '26 19:05

chqrlie