I'd like to create a macro that spits out an existent constant.
There are multiple constants and they all follow the form PREFIX_COMPONENT_ERROR.
Example code:
#include <stdlib.h>
enum {
MODULE_ERROR_COMP1_ERROR1 = 0,
MODULE_ERROR_COMP1_ERROR2,
MODULE_ERROR_COMP1_ERROR3,
MODULE_ERROR_COMP2_ERROR1,
MODULE_ERROR_COMP2_ERROR2,
MODULE_ERROR_COMP2_ERROR3,
};
static void* some_function (const char *restrict input);
#define EMPTY(...)
#define DEFER(...) __VA_ARGS__ EMPTY()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__
#define PASTER(x, y) x ## _ ## y
#define MODULE_ERROR some_function ("module error")
#define ERROR_PREFIX DEFER(MODULE_ERROR)
#define GENERATE_ERROR_(prefix, component, error) PASTER(DEFER(PASTER(prefix, component)), error)
#define GENERATE_ERROR(prefix, component, error) EXPAND(GENERATE_ERROR_(prefix, component, error))
static void* some_function (const char *restrict input) {
/*
* Does something with the input and returns some data,
* but for simplicity let's assume it just passes the input through.
*/
return (input);
}
int main (int argc, char **argv) {
/* Generate enum via PP macros, for instance: */
for (size_t i = 0; 3 > i; ++i) {
int error_code = 0;
void *common_error = ERROR_PREFIX;
if (0 == i) {
error_code = GENERATE_ERROR (ERROR_PREFIX, COMP1, ERROR1);
}
else if (1 == i) {
error_code = GENERATE_ERROR (ERROR_PREFIX, COMP2, ERROR3);
}
else {
error_code = GENERATE_ERROR (ERROR_PREFIX, COMP2, ERROR2);
}
/* Do something with error_code and common_error. */
}
return (EXIT_SUCCESS);
}
I wonder if what I want to do is even possible with simple PP directives in the first place.
The first issue is that I cannot use the concatenation macro PASTER twice, because the PP always chokes on the inner PASTER() call.
Converting that to a three-parameter macro such as:
#define PASTER(x, y, z) x ## _ ## y ## _ ## z
#define GENERATE_ERROR_(prefix, component, error) PASTER(prefix, component, error)
will expand prefix, which I do not want to happen and will run into an error anyway.
Using something like PASTER(OBSTRUCT(prefix), component, error) will likewise fail on concatenation.
I'm fully aware that this WOULD work, but I don't like it:
#define MODULE_ERROR_FUNC some_function ("module error")
#define ERROR_PREFIX MODULE_ERROR
#define GENERATE_ERROR_(prefix, component, error) PASTER(prefix, component, error)
#define GENERATE_ERROR(prefix, component, error) GENERATE_ERROR_(prefix, component, error)
/* [...] */
void *common_error = MODULE_ERROR_FUNC;
Is there really no way to let ERROR_PREFIX be expanded only once in the GENERATE_ERROR macro (i.e., to MODULE_ERROR) and otherwise have it expand to the function call (i.e., some_function ("module error"))?
#define GENERATE_ERROR(prefix, component, error) prefix ## _ ## component ## _ ## error— and then invokingGENERATE_ERROR(MODULE_PREFIX, COMP1, ERROR1)?PROJECT_LONG_SUBMODULE_ERRORyou'd like to avoid typing it all the time, especially if you use macros internally anyway.#define GENERR(component, error) GENERATE_ERROR(PROJECT_LONG_SUBMODULE_ERROR, component, error)to shorten the long names — invokingGENERR(COMPONENT2, ERROR2)to getPROJECT_LONG_SUBMODULE_ERROR_COMPONENT2_ERROR2as the error name?PROJECT_LONG_SUBMODULE_ERRORwon't be expanded during the expansion ofGENERR(i.e., why is it painted blue in that context?) I'd accept it. :)