Question

I am replacing macros in a large C99 code base with inline functions to see if the compiler can do a better job optimizing. There are a lot of macros which expand to a data structure. The code uses them not as functions, but as a replacement for the data structure itself.

For example...

#define AvARRAY(av)     ((av)->sv_u.svu_array)

AvARRAY(av)[--key] = &PL_sv_undef;

Not only is there a lot of code which does this, published code outside of my control does this, so I would rather leave this idiom in place if possible.

Is there a way to define an inline function version of AvARRAY which is compatible with the sort of code above?

Was it helpful?

Solution

Yes, you can use the return value without assigning it to a variable.

However, in general case it is not possible to replace this macro with a function. The whole point of using macros in for this purpose is that macros can "evaluate" to lvalues. Functions in C cannot produce lvalues, unfortunately. In other words, no, in general case you can't directly replace such macros with a functions.

But in specific case it could be different. Do they really use those macros as lvalues? In your specific example it is not used as an lvalue, so in your case you can just do

inline whatever_type_it_has *AvARRAY(struct_type *av)
{
  return av->sv_u.svu_array;
}

and use it later exactly as it is used in your example

AvARRAY(av)[--key] = &PL_sv_undef;

But if somewhere else in the code you have something like

AvARRAY(av) = malloc(some_size);

or

whatever_type_it_has **pptr = &AvARRAY(av);

then you'll be out of luck. The function version will not work, while the original macro will.

The only way to [almost] fully "emulate" the functionality of macro with a function in this case is to lift it to a higher level of indirection, i.e. assume that the function always returns a pointer to the target data field

inline whatever_type_it_has **AvARRAY_P(struct_type *av)
{
  return &av->sv_u.svu_array;
}

In that case you will have to remember to dereference that pointer every time

(*(AvARRAY_P(av))[--key] = &PL_sv_undef;

but this will work

*AvARRAY_P(av) = malloc(some_size);
whatever_type_it_has **pptr = &*AvARRAY_P(av);

But this will not work with bit-fields, while the macro version will.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top