我想创建一个吐出一个现有常量的宏。
有多个常量,它们都遵循PREFIX_COMPONENT_ERROR
的形式。
示例代码:
#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);
}
我想知道我想做的事情是否甚至可以通过简单的PP指令实现。
第一个问题是我不能使用串联宏PASTER
两次,因为PP总是在内部PASTER()
调用上阻塞。
将其转换为三参数宏,例如:
#define PASTER(x, y, z) x ## _ ## y ## _ ## z
#define GENERATE_ERROR_(prefix, component, error) PASTER(prefix, component, error)
将扩展为prefix
,我不想发生这种情况,无论如何都会遇到错误。
使用PASTER(OBSTRUCT(prefix), component, error)
之类的东西同样会在连接时失败。
我完全知道这是可以的,但是我不喜欢它:
#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;
真的没有办法让ERROR_PREFIX
在GENERATE_ERROR
宏中仅扩展一次(即扩展为MODULE_ERROR
),否则将其扩展为函数调用(即some_function ("module error")
)吗?
我对看到您的问题的立即反应是“您过于复杂了!”例如,怎么了:
#define GENERATE_ERROR(prefix, component, error) prefix ## _ ## component ## _ ## error
然后调用:
GENERATE_ERROR(MODULE_PREFIX, COMP1, ERROR1)
部分回答“什么问题?”是“在此示例中并不明显,但是当前缀类似PROJECT_LONG_SUBMODULE_ERROR
时,您要避免一直输入它”。可以,但是您可以考虑:
#define GENERR(component, error) GENERATE_ERROR(PROJECT_LONG_SUBMODULE_ERROR, component, error)
以缩短长名称-调用
GENERR(COMPONENT2, ERROR2)
获取错误名称:
PROJECT_LONG_SUBMODULE_ERROR_COMPONENT2_ERROR2
为什么在扩展
PROJECT_LONG_SUBMODULE_ERROR
时不扩展GENERR
(即为什么在这种情况下将其涂成蓝色)?
它不是漆成蓝色;我只是不会创建具有该名称的宏,因此没有任何要扩展的宏—就像在调用COMPONENT2
时不应扩展的宏ERROR2
或GENERR
一样。您可能有:
#define PLS_ERR PROJECT_LONG_SUBMODULE_ERROR
#define GENERR(component, error) GENERATE_ERROR(PLS_ERR, component, error)
您会创建长名。如果您有以下问题,就会出现:
#define PROJECT_LONG_SUBMODULE_ERROR pink_elephant
然后,您得到了不必要的扩展,但是您可以通过不定义项目的长子模块名称宏来避免这种情况。
您也可以拥有:
#define GENCOMPERR(err) GENERATE_ERROR(PLS_ERR, COMPONENT2, err)
依此类推,因此您可以调用:
GENCOMPERR(ERROR2)
并获得全部价值:
PROJECT_LONG_SUBMODULE_ERROR_COMPONENT2_ERROR2