首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C宏-避免宏扩展

C宏-避免宏扩展
EN

Stack Overflow用户
提问于 2013-12-29 06:43:00
回答 3查看 553关注 0票数 3

我有以下宏

代码语言:javascript
复制
#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,..although,我相信这个答案是针对一个完全不同的问题。

我所做的是

代码语言:javascript
复制
#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); \
}

但是这仍然给了我和以前一样的输出。

有办法做到这一点吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-12-29 06:45:03

您可以将REG_PWR_CTRLREG_FIFO_CTL作为枚举的值,例如

代码语言:javascript
复制
  enum registers_en {
     REG__NONE,
     REG_PWR_CTRL = 0x2d,
     REG_FIFO_CTL = 0x38,
  };

然后,REG_PWR_CTRL成为某个枚举值的真正标识符,而不是在其他东西中进行宏扩展(因为enum定义不是宏定义,也不是由预处理器处理的)。

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

请注意,预处理器在概念上是编译器的第一阶段:即使在像当前GCC 4.8这样的编译器中,预处理器不是外部程序,而是通过libcpp内部库实现的,编译器的工作方式是首先预处理源代码并获得词位流,然后出现的REG_PWR_CTRL仍然保持为lexemes (而不是#define REG_PWR_CTRL 0x2d时的文字常量0x2d )。

您需要阅读更多关于预处理cpp的内容,并养成查看预处理形式的习惯。

enum-s的另一个优点是,如果使用调试信息(例如gcc -g)编译调试信息,那么调试器gdb就知道enum

票数 4
EN

Stack Overflow用户

发布于 2013-12-29 07:06:13

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

代码语言:javascript
复制
#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;
}

输出:

代码语言:javascript
复制
REG_PWR_CTRL = 0X2D
REG_PWR_CTRL = 0X2D; num = 0X5
票数 4
EN

Stack Overflow用户

发布于 2013-12-29 10:31:40

在简单的事情上使用宏。

这是因为:

  • 您有更多可读的代码
  • 调试更容易,因为调试器具有帮助您的符号。
  • 它们很难调试。

所以只要用函数来处理复杂的事情。将宏用于简单的内容

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20822811

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档