我可以在 C 中使用宏来定义宏吗?
Can I define a macro using a macro in C?
我有一组像这样的#defines:
#define MODULE1_PINMASK 0x1
#define MODULE2_PINMASK 0x2
#define MODULE3_PINMASK 0x3
其中 pinmask 的值取决于第二个参数:
#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
如果以后的任何时候,我都会做出改变,例如:
#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */
我还需要更改密码掩码:
#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */
我正在尝试通过不必手动更改 pinmask 来自动执行该过程。到目前为止,我已经得到这些宏来提取 MODULEX_PORT_PIN 的第二个参数(在这种情况下我不关心第一个参数):
#define GET_SECOND(X, Y) Y
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN)
如果我在函数中使用它们,我会得到正确的结果,例如:
uint8_t pinmask=0x0;
switch (GET_PIN(MODULE2_PORT_PIN))
{
case 1:
pinmask = 0x1;
break;
case 2:
pinmask = 0x2;
break;
case 3:
pinmask = 0x3;
break;
default:
break;
}
printf ("%#x", pinmask); /* prints "0x2" */
但我想将 pinmasks 保留为#defines。有没有办法实现一个 #define GET_PINMASK
宏,它使用 switch case 来定义 pinmask?我的目标是:
#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN))
在这种情况下会将 MODULE1_PINMASK 定义为 0x1。
编辑:#define MODULE1_PORT_PIN A,1
中的第二个参数是 uint8_t 而不是十六进制值,所以我不能直接传递它。
我觉得你可能想多了。如果每个 MODULEn_PORT_PIN
定义的第二个字段总是 integer constant expression,那么这应该有效:
#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
#define GET_SECOND(X, Y) (Y)
#define PIN_TO_MASK(PIN) (1ul << GET_SECOND(PIN))
#define MODULE1_PINMASK PIN_TO_MASK(MODULE1_PORT_PIN)
#define MODULE2_PINMASK PIN_TO_MASK(MODULE2_PORT_PIN)
#define MODULE3_PINMASK PIN_TO_MASK(MODULE3_PORT_PIN)
从你的问题中不清楚第二个字段是否可以是整型常量表达式以外的东西。如果第二个字段涉及 enum
常量,那么 MODULEn_PINMASK
宏仍然可以在除 #if
表达式之外的任何上下文中使用。如果涉及到 变量,那么它们只能在函数体内使用。 (因为这是 C 而不是 C++,所以即使变量是 const
也是如此。)
没有办法避免必须单独编写每个 #define
。如果这是一个问题,您应该考虑编写一个生成 #define
列表的程序。在构建时从您自己发明的 DSL 生成源代码是一种被低估的技术。
您是否考虑过使用 x-macros?
您首先为条目列表创建摘要 #define
:
#define CREATE_LIST() \
ENTRY(1, A, 0x1) \
ENTRY(2, A, 0x2) \
ENTRY(3, A, 0x3)
然后为 ENTRY
的不同定义调用列表:
// Get the number of entries. Creates something like:
// const uint8_t PIN_COUNT = 0 + 1 + 1 + 1;
#define ENTRY(number, x, y) + 1
const uint8_t PIN_COUNT = \
CREATE_LIST()
;
#undef ENTRY
// Array of first parameters
#define ENTRY(number, x, y) #x ,
const char * Pin_names[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
// Array of second parameters
#define ENTRY(number, x, y) y,
const uint8_t Pin_masks[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
// Array of module names
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) ,
const char * Module_names[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
预处理器会将其扩展为:
const uint8_t PIN_COUNT =
+ 1 + 1 + 1
;
const char * Pin_names[PIN_COUNT] =
{
"A" , "A" , "A" ,
};
const uint8_t Pin_masks[PIN_COUNT] =
{
0x1, 0x2, 0x3,
};
const char * Module_names[PIN_COUNT] =
{
"MODULE1", "MODULE2", "MODULE3"
};
可能性是无限的。它的可读性较差,但可能更易于维护。
我有一组像这样的#defines:
#define MODULE1_PINMASK 0x1
#define MODULE2_PINMASK 0x2
#define MODULE3_PINMASK 0x3
其中 pinmask 的值取决于第二个参数:
#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
如果以后的任何时候,我都会做出改变,例如:
#define MODULE1_PORT_PIN A,1 /* changes to #define MODULE1_PORT_PIN A,4 */
我还需要更改密码掩码:
#define MODULE1_PINMASK 0x1 /* then becomes #define MODULE1_PINMASK 0x4 */
我正在尝试通过不必手动更改 pinmask 来自动执行该过程。到目前为止,我已经得到这些宏来提取 MODULEX_PORT_PIN 的第二个参数(在这种情况下我不关心第一个参数):
#define GET_SECOND(X, Y) Y
#define GET_PIN(PORT_PIN) GET_SECOND(PORT_PIN)
如果我在函数中使用它们,我会得到正确的结果,例如:
uint8_t pinmask=0x0;
switch (GET_PIN(MODULE2_PORT_PIN))
{
case 1:
pinmask = 0x1;
break;
case 2:
pinmask = 0x2;
break;
case 3:
pinmask = 0x3;
break;
default:
break;
}
printf ("%#x", pinmask); /* prints "0x2" */
但我想将 pinmasks 保留为#defines。有没有办法实现一个 #define GET_PINMASK
宏,它使用 switch case 来定义 pinmask?我的目标是:
#define MODULE1_PINMASK ASSIGN_PINMASK(GET_PIN(MODULE1_PORT_PIN))
在这种情况下会将 MODULE1_PINMASK 定义为 0x1。
编辑:#define MODULE1_PORT_PIN A,1
中的第二个参数是 uint8_t 而不是十六进制值,所以我不能直接传递它。
我觉得你可能想多了。如果每个 MODULEn_PORT_PIN
定义的第二个字段总是 integer constant expression,那么这应该有效:
#define MODULE1_PORT_PIN A,1
#define MODULE2_PORT_PIN A,2
#define MODULE3_PORT_PIN A,3
#define GET_SECOND(X, Y) (Y)
#define PIN_TO_MASK(PIN) (1ul << GET_SECOND(PIN))
#define MODULE1_PINMASK PIN_TO_MASK(MODULE1_PORT_PIN)
#define MODULE2_PINMASK PIN_TO_MASK(MODULE2_PORT_PIN)
#define MODULE3_PINMASK PIN_TO_MASK(MODULE3_PORT_PIN)
从你的问题中不清楚第二个字段是否可以是整型常量表达式以外的东西。如果第二个字段涉及 enum
常量,那么 MODULEn_PINMASK
宏仍然可以在除 #if
表达式之外的任何上下文中使用。如果涉及到 变量,那么它们只能在函数体内使用。 (因为这是 C 而不是 C++,所以即使变量是 const
也是如此。)
没有办法避免必须单独编写每个 #define
。如果这是一个问题,您应该考虑编写一个生成 #define
列表的程序。在构建时从您自己发明的 DSL 生成源代码是一种被低估的技术。
您是否考虑过使用 x-macros?
您首先为条目列表创建摘要 #define
:
#define CREATE_LIST() \
ENTRY(1, A, 0x1) \
ENTRY(2, A, 0x2) \
ENTRY(3, A, 0x3)
然后为 ENTRY
的不同定义调用列表:
// Get the number of entries. Creates something like:
// const uint8_t PIN_COUNT = 0 + 1 + 1 + 1;
#define ENTRY(number, x, y) + 1
const uint8_t PIN_COUNT = \
CREATE_LIST()
;
#undef ENTRY
// Array of first parameters
#define ENTRY(number, x, y) #x ,
const char * Pin_names[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
// Array of second parameters
#define ENTRY(number, x, y) y,
const uint8_t Pin_masks[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
// Array of module names
#define ENTRY(number, x, y) STRINGIFY(MODULE ## number) ,
const char * Module_names[PIN_COUNT] =
{
CREATE_LIST()
};
#undef ENTRY
预处理器会将其扩展为:
const uint8_t PIN_COUNT =
+ 1 + 1 + 1
;
const char * Pin_names[PIN_COUNT] =
{
"A" , "A" , "A" ,
};
const uint8_t Pin_masks[PIN_COUNT] =
{
0x1, 0x2, 0x3,
};
const char * Module_names[PIN_COUNT] =
{
"MODULE1", "MODULE2", "MODULE3"
};
可能性是无限的。它的可读性较差,但可能更易于维护。