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?
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;
}
}
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