我有以下macros
#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
我遇到了很多关于增加额外间接级别的post。
我尝试了这里描述的答案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
保持为词位(不像当你#define 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
使用宏来做简单的事情。
这是因为:
所以只需使用复杂的东西的功能。 使用宏来做简单的事情