如何使用XMACROs将宏参数值转换为字符串,而不是转换传递的参数本身
在我在社区内做了足够的研究之后,我将这个问题发布在这里。然而,我还没有找到一个合适的解决方案。所以,我把我的问题贴在这里如何使用XMACROs将宏参数值转换为字符串,而不是转换传递的参数本身,c,for-loop,automation,x-macros,C,For Loop,Automation,X Macros,在我在社区内做了足够的研究之后,我将这个问题发布在这里。然而,我还没有找到一个合适的解决方案。所以,我把我的问题贴在这里 #define EXPAND_AS_ENUMERATION(a) CODE_##a, #define EXPAND_AS_ARRAY(a) a, #define CODE_TABLE(EXPAND)\ EXPAND(0x00E30054uL)\ EXPAND(0x00ED3581uL)\ EXPAND(0x00ED3983uL)\ EXPAN
#define EXPAND_AS_ENUMERATION(a) CODE_##a,
#define EXPAND_AS_ARRAY(a) a,
#define CODE_TABLE(EXPAND)\
EXPAND(0x00E30054uL)\
EXPAND(0x00ED3581uL)\
EXPAND(0x00ED3983uL)\
EXPAND(0x00EE0368uL)\
EXPAND(0x00EE0368uL)\
EXPAND(0x00D01087uL)\
EXPAND(0x00ED4181uL)\
EXPAND(0x00505602uL)\
// Actual Event IDs which need to be selected at run time
#define SWC_FAULT_CODE_0x00E30054_EVENT 113
#define SWC_FAULT_CODE_0x00ED3581_EVENT 213
#define SWC_FAULT_CODE_0x00ED3983_EVENT 432
#define SWC_FAULT_CODE_0x00EE0368_EVENT 411
#define SWC_FAULT_CODE_0x00EE0368_EVENT 311
#define SWC_FAULT_CODE_0x00D01087_EVENT 231
#define SWC_FAULT_CODE_0x00ED4181_EVENT 471
#define SWC_FAULT_CODE_0x00505602_EVENT 419
#define prefix_str SWC_FAULT_CODE
#define postfix_str _EVENT
#define Get_EventID_FROM_CODE(code) ????? // ex: when code= 0x00ED3581, then it should return SWC_FAULT_CODE_0x00ED3581_EVENT macro or it's value 213
#define Get_EventID_FROM_ENUM(code_enum) ????? // ex: when code_enum= CODE_0x00ED3581, then it should return SWC_FAULT_CODE_0x00ED3581_EVENT macro or it's value 213
#define Get_CodeEnumName(code) ????? // ex: when code = 0x00ED3581, then it should return DTC_0x00ED3581 which is enum element
typedef enum
{
CODE_TABLE(EXPAND_AS_ENUMERATION)
CODE_COUNT
}codeList_t ;
void Cycle_1ms(const uint32 code)
{
// Based on code value, I want to get the macro value of SWC_FAULT_CODE_0xZZZZZZZZ_EVENT.
// ex: when code = 0x00ED3581, then eventID = SWC_FAULT_CODE_0x00ED3581_EVENT = 213
uint16 eventID_FromCode = Get_EventID(code);
}
void Cycle_1ms_anotherFunc(codeList_t code_enum)
{
// Based on code value, I want to get the macro value of SWC_FAULT_CODE_0xZZZZZZZZ_EVENT.
// ex: when code = 0x00ED3581, then eventID = SWC_FAULT_CODE_0x00ED3581_EVENT = 213
uint16 eventID_FromCodeEnum = Get_EventID_FROM_ENUM(code_enum);
}
void callback_func(uint32 code, uint8* buf)
{
// here, based on code value Get_CodeEnumName() should provide the enum element for that code. ex: when code= 0x00ED3581, enum_var = DTC_0x00ED3581
codeList_t enum_var = Get_CodeEnumName(code);
}
在这里,CODE_表将根据不同的项目和此表中包含的元素数量进行更改。在阅读了几篇关于Xmacros的文章和主题之后,我想到在这里使用Xmacros概念,以避免循环和大量使用RAM内存。您不能将X宏与运行时输入一起使用,它们在编译时被扩展。因此,如果需要基于运行时值进行表查找,那么它们不是解决方案 但是,您可以使用X宏生成查找表,然后使用幻数编译时常量展开为枚举,而枚举又对应于查找表索引:
#define GET_EVENT_ID(code) LOOKUP[CODE_##code]
GET_事件ID扩展为类似于查找[code_0x00ED3581]
的内容,这是一种数组访问
此外,“事件”可以与同一个X宏列表中的代码捆绑在一起,即使您不需要在每个宏中使用它们。还要注意的是,在X宏列表中有重复的项,这将无法工作,因为您计划使用它生成唯一的枚举常量。我们可以这样改变它:
#define CODE_TABLE(X) \
/* code event */ \
X(0x00E30054uL, 113) \
X(0x00ED3581uL, 213) \
X(0x00ED3983uL, 432) \
X(0x00EE0368uL, 411) \
X(0x00D01087uL, 231) \
X(0x00ED4181uL, 471) \
X(0x00505602uL, 419) \
然后将SWC#U故障创建为枚举常量,而不是#定义:
然后是用于查找表索引的枚举:
// create enums like CODE__0x00ED3581:
#define EXPAND_AS_ENUMERATION(code, event) CODE_##code,
typedef enum
{
CODE_TABLE(EXPAND_AS_ENUMERATION)
CODE_COUNT
}code_list_t ;
一个完整的例子:
#include <inttypes.h>
#include <stdio.h>
#define CODE_TABLE(X) \
/* code event */ \
X(0x00E30054uL, 113) \
X(0x00ED3581uL, 213) \
X(0x00ED3983uL, 432) \
X(0x00EE0368uL, 411) \
X(0x00D01087uL, 231) \
X(0x00ED4181uL, 471) \
X(0x00505602uL, 419) \
// create SWC_FAULT_CODE_0x00ED3581_EVENT constants:
#define SWC_FAULT(code,event) SWC_FAULT_CODE_##code##_EVENT = event,
enum
{
CODE_TABLE(SWC_FAULT)
};
// create enums like CODE__0x00ED3581:
#define EXPAND_AS_ENUMERATION(code, event) CODE_##code,
typedef enum
{
CODE_TABLE(EXPAND_AS_ENUMERATION)
CODE_COUNT
}code_list_t ;
// create look-up table containing SWC_FAULT_CODE_0x00ED3581_EVENT
// use designated initializers to get [CODE__0x00ED3581] = SWC_FAULT_CODE_0x00ED3581_EVENT
#define LOOKUP_TABLE(code,event) [CODE_##code] = SWC_FAULT_CODE_##code##_EVENT,
static const uint32_t LOOKUP[CODE_COUNT] =
{
CODE_TABLE(LOOKUP_TABLE)
};
_Static_assert(sizeof LOOKUP/sizeof *LOOKUP == CODE_COUNT, "LOOKUP table corrupt");
#define GET_EVENT_ID(code) LOOKUP[CODE_##code]
int main()
{
printf("0x%.8" PRIX32 " = %"PRIu32 "\n", 0x00ED3581uL, GET_EVENT_ID(0x00ED3581uL));
return 0;
}
您可以将
Get\u EventID\u FROM\u code
扩展为一个非常长的三元运算符链(?:
)。XMacro可以在另一个宏中展开,以实现此目的
这样可以避免使用函数。此外,该解决方案还接受整数文本和变量的任何格式。如果可能的话,它会扩展为一个真正的C常量。唯一的缺点是参数表达式的计算,但这是宏的常见问题
#include <inttypes.h>
#include <stdio.h>
#define CODE_TABLE(X, ...) \
X(0x00E30054uL, 113, __VA_ARGS__) \
X(0x00ED3581uL, 213, __VA_ARGS__) \
X(0x00ED3983uL, 432, __VA_ARGS__) \
X(0x00EE0368uL, 411, __VA_ARGS__) \
X(0x00D01087uL, 231, __VA_ARGS__) \
X(0x00ED4181uL, 471, __VA_ARGS__) \
X(0x00505602uL, 419, __VA_ARGS__) \
// expands to -1 for invalid code
#define GET_EVENT_ID_(CODE,ENUM,VAR) (VAR) == (CODE) ? ENUM :
#define GET_EVENT_ID(code_var) (CODE_TABLE(GET_EVENT_ID_, code_var) -1)
int main()
{
#define DBG(CODE) \
printf("%s 0x%08lx = %d\n", #CODE, (unsigned long)(CODE), GET_EVENT_ID(CODE))
DBG(0x00ED3983uL);
DBG(0x00ED3983);
DBG(0xED3983);
int32_t x = 0x00D01087uL;
DBG(x);
// expand to a true constant if possible
struct X { char x[GET_EVENT_ID(0xED3983)]; };
printf("%zi\n", sizeof(struct X));
return 0;
}
在函数中,
code
是一个变量。预处理器无法知道其值。您可以将Get_uu
宏转换为查找表或函数,其主体是X宏的另一个扩展,例如case X:return SWC_FAULT_35;u code_35;X#u事件
。但只有当code
是文本而不是文本时,它才起作用variable@tstanisl是的,这确实是这个答案的前两句话所说的。但是,即使是对输入的细微修改,它也会失败,比如:GET\u EVENT\u ID(0x00ED3581uL)
vsGET\u EVENT\u ID(0x00ED3581uL)
vsGET_EVENT_ID(0x00ED3581)
或GET_EVENT_ID(0xED3581)
我实际上会更简单,因为它会扩展到真常数,不是查找中的某个入口table@tstanisl是的,因此,如果您希望调用者使用各种版本,可以删除ul并从宏内部调用UINT32_C(0x00ED3581)
。有各种各样的改进可以做,我只是演示了粗略的概念。
mov edx, 213
mov esi, 15545729
xor eax, eax
mov edi, OFFSET FLAT:.LC0
#include <inttypes.h>
#include <stdio.h>
#define CODE_TABLE(X, ...) \
X(0x00E30054uL, 113, __VA_ARGS__) \
X(0x00ED3581uL, 213, __VA_ARGS__) \
X(0x00ED3983uL, 432, __VA_ARGS__) \
X(0x00EE0368uL, 411, __VA_ARGS__) \
X(0x00D01087uL, 231, __VA_ARGS__) \
X(0x00ED4181uL, 471, __VA_ARGS__) \
X(0x00505602uL, 419, __VA_ARGS__) \
// expands to -1 for invalid code
#define GET_EVENT_ID_(CODE,ENUM,VAR) (VAR) == (CODE) ? ENUM :
#define GET_EVENT_ID(code_var) (CODE_TABLE(GET_EVENT_ID_, code_var) -1)
int main()
{
#define DBG(CODE) \
printf("%s 0x%08lx = %d\n", #CODE, (unsigned long)(CODE), GET_EVENT_ID(CODE))
DBG(0x00ED3983uL);
DBG(0x00ED3983);
DBG(0xED3983);
int32_t x = 0x00D01087uL;
DBG(x);
// expand to a true constant if possible
struct X { char x[GET_EVENT_ID(0xED3983)]; };
printf("%zi\n", sizeof(struct X));
return 0;
}
0x00ED3983uL 0x00ed3983 = 432
0x00ED3983 0x00ed3983 = 432
0xED3983 0x00ed3983 = 432
x 0x00d01087 = 231
432