Is there a C preprocessor macro to print out a str

2019-06-07 14:34发布

问题:

As far as I can tell, there's no way to print out a struct value in C.

i.e., this doesn't fly:

typedef struct {
    int a;
    double b;
} stype

stype a;

a.a=3;
a.b=3.4;

printf("%z", a);

instead you have to say:

printf("a: %d\n", a.a);
printf("b: %f\n", a.b);

This seems like a perfect place where you could use a macro to save a vast amount of typing for arbitrary structs.

Is the C preprocessor powerful enough to perform this transformation?

回答1:

I think that the simplest solution (and maybe the most beautiful) is to use a function to print your specific struct.

void display_stype(stype *s)
{
    printf("a: %d\n", s->a);
    printf("b: %f\n", s->b);
}

If your struct changed, you can adapt in one place your code easily.



回答2:

I would make two macros, like this:

#define STYPE_FMT "%d %f"
#define STYPE_MEMS(s) (s).a, (s).b

Then you can do something like:

printf("hello %s, stype: " STYPE_FMT "\n", "world", STYPE_MEMS(my_s));

What makes this approach superior to a "print function" for the structure is that you can use the macros with any of the printf-family functions you like, and combine printing of other data.

You could get even fancier and instead do:

#define STYPE_FMT "%d %.*f"
#define STYPE_MEMS(s) (s).a, 6, (s).b
#define STYPE_MEMS_PREC(s, p) (s).a, (int)(p), (s).b

and then you can use the default precision or choose a custom precision.



回答3:

Is the C preprocessor powerful enough to perform this transformation?

Yes, it is, but then you have to repeat the entire struct declaration within the macro which kind of defeats the purpose. You could have something like this:

STRUCT_PRINTF(
    a
  , ( int, a )
    ( double, b )
);

and then you would need a pretty complex implementation of such macro, with lots and lots of helper macros/functions.



回答4:

No, the C preprocessor is mostly a textual macro replacement tool. It doesn't know about types and structures of C.



回答5:

You cannot iterate on struct members in C, either dynamically or statically (nor in C++). There is no reflection in C.

Thus, there is no way to make the preprocessor perform this transformation.



回答6:

You could make macro for this:

#define PRINT_MEMBER(M) do {printf(#M": %d\n", (int) M;} while(0)

and then print it like this:

PRINT_MEMBER(a.a);
PRINT_MEMBER(b->b);

You might wanna define multiple of these to cover different types (e.g. floats, doubles, print as hex). Unfortunately there is no good workaround for this as C preprecossor has no notion of what types are, e.g. you can't use something like switch(typeof(M)) { case int: printf(.."%d"..; break; ...} .