[英]During C macro expansion, is there a special case for macros that would expand to “/*”?
[英]C Macros - avoiding macro expansion
我有以下宏
#define REG_PWR_CTRL 0x2D
#define REG_FIFO_CTL 0x38
#define VERBOSE(...) \
if(verbose) \
printf(__VA_ARGS__);
#define READ_REGISTER(i2c_dev_file, REGISTER, variable) \
{ \
variable = i2c_smbus_read_byte_data(i2c_dev_file, REGISTER); \
}
#define WRITE_REGISTER_VERBOSE(i2c_dev_file, REGISTER, value) \
{ \
short int var = 0; \
i2c_smbus_write_byte_data(i2c_dev_file, REGISTER, value); \
usleep(100); \
READ_REGISTER(i2c_dev_file, REGISTER, var); \
VERBOSE(#REGISTER " :0x%02X\n", var); \
}
我希望REGISTER
字段不会在以下行中展开
VERBOSE(#REGISTER " :0x%02X\\n", var); \\
例如,我写的时候
WRITE_REGISTER_VERBOSE(i2c_dev_fd, REG_PWR_CTRL, 0x1A);
WRITE_REGISTER_VERBOSE(i2c_dev_fd, REG_FIFO_CTL, 0xC6);
我得到了输出
0x2D :0x1A
0x38 :0xC6
我想获得
REG_PWR_CTRL :0x1A
REG_FIFO_CTL :0xC6
我遇到了许多关于添加额外级别间接的帖子。
我尝试了这里描述的答案https://stackoverflow.com/a/2653351/1761555 ..尽管我相信这个答案完全是针对不同的问题..
我做的是
#define STRINGIFY(label) (#label)
#define WRITE_REGISTER_VERBOSE(i2c_dev_file, REGISTER, value) \
{ \
short int var = 0; \
i2c_smbus_write_byte_data(i2c_dev_file, REGISTER, value); \
usleep(100); \
READ_REGISTER(i2c_dev_file, REGISTER, var); \
VERBOSE("%s :0x%02X\n", STRINGIFY(REGISTER), var); \
}
但这仍然给我与以前相同的输出
有没有办法实现这个目标?
您可以使REG_PWR_CTRL
和REG_FIFO_CTL
成为某些枚举的值,例如
enum registers_en {
REG__NONE,
REG_PWR_CTRL = 0x2d,
REG_FIFO_CTL = 0x38,
};
然后REG_PWR_CTRL
成为某个枚举值的实际标识符,并且不会在其他内容中进行宏扩展(因为enum
定义不是宏定义,并且不由cpp
预处理器处理 )。
因此,定义这样的枚举,并预处理您的源代码(例如,使用gcc -C -E yoursource.c > yoursource.i
)然后在预处理文件中查看(例如,使用less yoursource.i
)。 所有出现的REG_PWR_CTRL
仍然存在。
请注意,预处理器在概念上是编译器的第一阶段:即使在当前GCC 4.8等编译器中,预处理器不是外部程序,而是通过libcpp内部库实现,编译器首先预处理源代码并获取流的词位 ,然后的出现REG_PWR_CTRL
留为词位(而不是字面常量0x2d
当你为#define REG_PWR_CTRL 0x2d
...)。
您需要阅读有关预处理器cpp的更多信息,并养成查看预处理表单的习惯。
enum
-s的另一个优点是,如果使用调试信息(例如gcc -g
)编译调试信息,则调试器gdb
知道enum
。
为简单起见,我修改了代码:
#include <stdio.h>
#define REG_PWR_CTRL (0x2D)
#define GET_VAR_NAME(var) (#var)
#define VERBOSE(...) (printf(__VA_ARGS__))
#define ANOTHER_LAYER(arg) ( \
VERBOSE("%s = %#X; %s = %#X\n", \
GET_VAR_NAME(REG_PWR_CTRL), REG_PWR_CTRL, \
GET_VAR_NAME(arg), arg) \
) \
int main(void)
{
int num = 5;
VERBOSE("%s = %#X\n", GET_VAR_NAME(REG_PWR_CTRL), REG_PWR_CTRL);
ANOTHER_LAYER(num);
return 0;
}
输出:
REG_PWR_CTRL = 0X2D
REG_PWR_CTRL = 0X2D; num = 0X5
使用宏来处理简单的事情。
这是因为:
所以只需将函数用于复杂的东西。 使用宏来表示简单的东西
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.