C宏 - 避免宏扩展

时间:2013-12-29 06:43:01

标签: c linux 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

我遇到很多关于增加额外间接水平的帖子 我尝试了这里描述的答案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); \
}

但这仍然给我与之前相同的输出

有没有办法实现这个目标?

3 个答案:

答案 0 :(得分:4)

您可以将REG_PWR_CTRLREG_FIFO_CTL设为某个枚举值,例如

  enum registers_en {
     REG__NONE,
     REG_PWR_CTRL = 0x2d,
     REG_FIFO_CTL = 0x38,
  };

然后REG_PWR_CTRL成为某个枚举值的真实标识符,并且不会在其他内容中进行宏扩展(因为enum定义不是宏定义,并且不由{{处理} 3}})。

因此,定义这样的枚举,并预处理您的源代码(例如,使用gcc -C -E yoursource.c > yoursource.i),然后在预处理文件中查找(例如使用less yoursource.i)。所有出现的REG_PWR_CTRL仍然存在。

请注意,预处理器在概念上是编译器的第一阶段:即使在当前cpp preprocessor之类的编译器中,预处理器外部程序,但通过{{3}实现在内部库中,编译器的工作原理是首先预处理源代码并获取GCC 4.8的流,然后REG_PWR_CTRL的出现保持为词位(而不是文字常量0x2d,就像你{ {1}} ......)。

您需要阅读有关预处理器libcpp的更多信息,并养成查看预处理表单的习惯。

#define REG_PWR_CTRL 0x2d - s的另一个优点是,如果使用调试信息(例如enum)编译调试信息,则调试器gcc -g知道gdb

答案 1 :(得分:4)

为简单起见,我修改了代码:

#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

答案 2 :(得分:1)

将宏用于简单的事情。

这是因为:

  • 你有更多可读代码
  • 调试器具有帮助您的符号,因此更易于调试
  • 他们很难调试。

所以只需将函数用于复杂的东西。将宏用于简单的东西