Let have a struct like this:
struct _Example {
int a;
int b;
int c;
} Example;
One function takes this struct by pointer and outputs the value of struct members. I want to print those values like this:
Example example;
func(&example);
if(example.a)
printf("%d", example.a);
if(example.b)
printf("%d", example.b);
if(example.c)
printf("%d", example.c);
How can I replace those multiple if
conditions with a loop?
The best way is probably type punning over union
. It allows you to use the same memory area with different variable representations, for example by giving each struct member individual names, while at the same time remaining able to loop through them.
#include <stdio.h>
typedef union {
struct // anonymous struct, requires standard C compiler
{
int a;
int b;
int c;
};
int array[3];
} Example;
int main (void)
{
Example ex = { .a=1, .b=2, .c=3 };
for(size_t i=0; i<3; i++)
{
printf("%d\n", ex.array[i]);
}
}
If you can't change the struct definition, then the second best is some pointer arithmetic through a character type. This takes much more care though, so that you don't end up writing code with poorly-defined behavior - you need to be aware of things like alignment and strict aliasing. Character types are preferred to work with in case the struct turns more complex with different types of members, because character types are safe from aliasing issues.
Assuming uint8_t
is a character type, then:
#include <stdio.h>
#include <stdint.h>
typedef union {
struct
{
int a;
int b;
int c;
};
} Example;
int main (void)
{
Example ex = { .a=1, .b=2, .c=3 };
uint8_t* begin = (uint8_t*)&ex;
uint8_t* end = begin + sizeof ex;
for(uint8_t* i=begin; i!=end; i+=sizeof(int))
{
printf("%d\n", *(int*)i);
}
}
The short answer is, you cannot do that easily. Members in structs are designed to be accessed by name, as opposed to elements in arrays which are designed to be indexed.
Computing addresses from offsets is a possibility but you still need to know the struct layout anyway — and on top, that layout can change with a compiler option or pragma.
Languages which carry type information into a more elaborate runtime environment, like C# and Java, allow you to enumerate struct members at run time, but C just creates an un-annotated data blob which you must know at compile time anyway, so you can as well enumerate the members explicitly. Of course you can use the usual C tricks; there is probably a serialization solution out there which generates code for accessing struct elements from some struct definition wrapped in a macro (ah, yes, the first google hit: https://gist.github.com/Rhomboid/8e48620badbb3d9b4c30).
The fact that you can index elements of arrays at run time is owed to the fact that the internal layout of an array is completely known (for example, it is defined to not contain padding).
Of course you can define a struct which holds an array of unions large enough to accommodate your largest element which carries its own type and "member" name information and then functions to interpret that information, computing the proper memory location, using the appropriate type cast and printf
conversion string at run time. In effect you'd emulate some of the features of more elaborate run time environments.
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