As a possible solution to your problem: "write a macro and then discard it, by replacing by an equivalent function", you can use prototyped function-like macros. They have some limitations, and must be used with some care. But they work almost the same way as a function.
#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA
xxPseudoPrototype(float, xxSUM_data, int x; float y; );
xxSUM_data xxsum;
#define SUM_intfloat(X, Y) ( xxsum = (xxSUM_data){ .x = (X), .y = (Y) }, \
xxsum.xxmacro__ret__ = xxsum.x + xxsum.y, \
xxsum.xxmacro__ret__)
I have explained the details here (mainly section 4, for function-like macros):
Macros faking functions
- The 1st line defines a macro that can be used to declare pseudoprototypes for macros.
- The 2nd line uses that macro providing such a pseudoprototype. It defines "formal" parameters of the desired types. It contains, in order, the "return" type desired for the macro, the name of a struct where the parameters of the macro will be held, and finally the parameters (with types!) of the macro. I prefer call them pseudoparameters.
- The 3rd line is an obligatory statement, which makes "real" the pseudoparameters. It declares a struct, that it is necessary to write. It defines a struct containing the "real" version of the pseudoparameters.
- Finally, the macro itself it is defined, as a chained list of expressiones, separated by comma operators. The first operand is used to "load" the arguments of the macro into the "real" typed parameters. The last operand is the "returning value", which has also the desired type.
Observe that the compiler does right and transparent diagnostics of types.
(However, it is necessary to have some care with these constructs, as explained in the link).
Now, if you can collect all the sentences of your macro as a chain of function-calls separated by commas, then you can obtain function-like macro, as you desired.
Moreover, you can easily convert it into a real function, since the list of parameters is already defined. The type-checking was already done, so everything will work fine.
In the example above, you have to replace all the lines (except the first), by these other ones:
#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA
float SUM_intfloat(int x, float y) { /* (1) */
xxPseudoPrototype(float, xxSUM_data, int x; float y; ); /* (2) */
xxSUM_data xxsum; /* (2) */
return /* (3) */
( xxsum = (xxSUM_data){ .x = x, .y = y }, /* (4) (5) (6) */
xxsum.xxmacro__ret__ = xxsum.x + xxsum.y, /* (5) (6) */
xxsum.xxmacro__ret__) /* (6) */
; /* (7) */
} /* (8) */
The replacement will follow a sistematic procedure:
(1) Macro header turned into function header. Semicolons (;) are replaced by commas (,).
(2) Declaration lines are moved inside function body.
(3) The "return" word is added.
(4) Macro arguments X, Y, are replaced by function parameters x, y.
(5) All ending "\"s are removed.
(6) All intermediante calculations and function calls are left untouched.
(7) Semicolon added.
(8) Closing function body.
Problem: Although this approach solves your needs, note that the function has duplicated its list of parameters. This is not good: pseudoprototypes and duplicates have to be erased:
float SUM_intfloat(int x, float y) {
return
( x + y )
;
}