簡體   English   中英

C宏 - 避免宏擴展

[英]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_CTRLREG_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM