GCC未能(?)扩展复杂的宏

时间:2017-09-11 21:18:48

标签: c gcc c-preprocessor

以下混乱的宏在visual studio和Keil ARM编译器下正确编译,但是对于ARM 6.3.1的GCC失败了:

#define DRV_ACFGCAL_REG_INDEX(regulator_name,register_num)  ((ACFG_CFG##register_num##_EN##regulator_name##_LSB+3)/4 + ((register_num-2)*8))
#define DRV_ACFGCAL_RESET_INDEX(reset_name,reg_offset)       ((ACFG_CFG##reg_offset##_R##reset_name##_LSB)+((reg_offset-1)*32))
#define DRV_ACFGCAL_INFO(rst,rst_reg,idx,docx,regi,vtr,pdcal) \
                                                             {                                       \
                                                             0                                      ,\
                                                             0                                      ,\
                                                             idx##_ACFG_IDX                         ,\
                                                             docx##_WORD_COUNT                      ,\
                                                             DRV_ACFGCAL_RESET_INDEX(rst,rst_reg)   ,\
                                                             DRV_ACFGCAL_REG_INDEX(rst,##regi##)   ,\
                                                             docx##_##vtr##_LSB                     ,\
                                                             docx##_##vtr##_OFFSET                  ,\
                                                             docx##_##pdcal##_VTRCAL_MASK           ,\
                                                             docx##_##pdcal##_VTRCAL_RESET_VALUE    ,\
                                                             }
#define DRV_ACFGCAL_INFOn(rst,rst_reg,idx,docx,regi,vtr,pdcal) \
                                                             {                                       \
                                                             0                                      ,\
                                                             0                                      ,\
                                                             idx##_ACFG_IDX                         ,\
                                                              docx##_WORD_COUNT                     ,\
                                                             DRV_ACFGCAL_RESET_INDEX(rst,rst_reg)   ,\
                                                             DRV_ACFGCAL_REG_INDEX(rst,##regi##)   ,\
                                                             0                                      ,\
                                                             0                                      ,\
                                                             0                                      ,\
                                                             0                                      ,\
                                                             }

/* Some blocks with reset bits don't have regulator bits. Deal with it by creating bogus values
 * that can be used to identify those blocks in code. */

#define ACFG_CFGNONE_ENDAC01_LSB    (NONE_INDEX*4)
#define ACFG_CFGNONE_ENDAC23_LSB    (NONE_INDEX*4)
#define ACFG_CFGNONE_ENDAC45_LSB    (NONE_INDEX*4)
#define ACFG_CFGNONE_ENREFCAL_LSB   (NONE_INDEX*4)
#define ACFG_CFGNONE_ENTESTADC_LSB  (NONE_INDEX*4)


#define ACFG_NONE_ENNONE_LSB        7
#define ACFG_NONE_ENNONE_OFFSET     2
#define ACFG_NONE_ENDAC01_LSB       ACFG_NONE_ENNONE_LSB
#define ACFG_NONE_ENDAC01_OFFSET    ACFG_NONE_ENNONE_OFFSET
#define ACFG_NONE_ENDAC23_LSB       ACFG_NONE_ENNONE_LSB
#define ACFG_NONE_ENDAC23_OFFSET    ACFG_NONE_ENNONE_OFFSET
#define ACFG_NONE_ENDAC45_LSB       ACFG_NONE_ENNONE_LSB
#define ACFG_NONE_ENDAC45_OFFSET    ACFG_NONE_ENNONE_OFFSET
#define ACFG_NONE_ENREFCAL_LSB      ACFG_NONE_ENNONE_LSB
#define ACFG_NONE_ENREFCAL_OFFSET   ACFG_NONE_ENNONE_OFFSET
#define ACFG_NONE_ENTESTADC_LSB     ACFG_NONE_ENNONE_LSB
#define ACFG_NONE_ENTESTADC_OFFSET  ACFG_NONE_ENNONE_OFFSET
#define NONE (2)
#define NONE_INDEX  (63)

#define ACFG_INFO_addr(block)  ((g_drv_acfg_info[block].m_index << 4) | FIRST_ACFG_BASE_ADDR)
#define DAC01_ACFG_IDX 1
#define DAC_WORD_COUNT 5
#define ACFG_CFG1_RDAC01_LSB 0
#define DAC_TESTA_T_VTR_LSB 1
#define DAC_TESTA_T_VTR_OFFSET 1
#define DAC_PDCAL_VTRCAL_MASK 0xf
#define DAC_PDCAL_VTRCAL_RESET_VALUE 0


typedef struct {
    unsigned m_bEnabled     : 1;
    unsigned m_caled        : 1; /**< 0 until calibration occurs. After being set, cal will not occur again */
    unsigned m_index        : 9; /**< The base index of the hardware block */
    unsigned m_count        : 5; /**< Number of registers in this hardware block */
    unsigned m_resetIdx     : 6; /**< which bit index (0-63) the reset for this block sits*/
    unsigned m_regulatorIdx : 6; /**< which group of 3 controls the regulator for this block, 63 for none*/
    unsigned m_vtrlsb       : 4; /**< Left bit shifts into the testa register of a block to
                                      place VTR on diaga */
    unsigned m_vtroffset    : 4; /**< Offset from base address of a block to the register containing
                                      the bit for VTR on diaga */
    unsigned m_vtrmask      : 8; /**< The mask of the calcode register for a given block */
    unsigned m_vtrcache     : 7; /**< The starting calcode for a given block */
} drv_acfg_info_t;

drv_acfg_info_t g_drv_acfg_info[] = {
/*                     rst   rst       idx      docx     acfg       VTR on       CAL 
 *                     name  reg#      name     name     reg#     diagA name    regname function
 *                     ------ ------ --------  --------  ----- ----------------- ------ ----- */
    DRV_ACFGCAL_INFO (DAC01,1,DAC01,DAC,NONE,TESTA_T_VTR,PDCAL),    //ACFG_BLK_DAC01,
};

预处理器似乎没有完全扩展的问题,正如错误所暗示的那样:

output/gcc_cortex_m3/simple/objs/main.c.o :
   + tests/simple/main.c
"C:/usr/gcc_arm/6_2017-q2-update"/bin/arm-none-eabi-gcc.exe   -J"C:/usr/gcc_arm/6_2017-q2-update"/arm-none-eabi/include -MD -MF output/gcc_cortex_m3/simple/objs/main.c.d  -E -J"C:/usr/gcc_arm/6_2017-q2-update"/arm-none-eabi/include -I. -D__MICROLIB  -include gcc_preinclude.h -E -Dsi4790     -O3 -Os -g -D_DEBUG --no-exceptions  -mthumb -mcpu=cortex-m3    -c -o output/gcc_cortex_m3/simple/objs/main.c.o tests/simple/main.c
tests/simple/main.c:17:87: error: pasting "," and "NONE" does not give a valid preprocessing token
                                                              DRV_ACFGCAL_REG_INDEX(rst,##regi##)   ,\
                                                                                       ^
tests/simple/main.c:91:5: note: in expansion of macro 'DRV_ACFGCAL_INFO'
     DRV_ACFGCAL_INFO (DAC01,1,DAC01,DAC,NONE,TESTA_T_VTR,PDCAL),    //ACFG_BLK_DAC01,
     ^~~~~~~~~~~~~~~~
tests/simple/main.c:91:41: error: pasting "NONE" and ")" does not give a valid preprocessing token
     DRV_ACFGCAL_INFO (DAC01,1,DAC01,DAC,NONE,TESTA_T_VTR,PDCAL),    //ACFG_BLK_DAC01,
                                         ^
tests/simple/main.c:17:90: note: in definition of macro 'DRV_ACFGCAL_INFO'
                                                              DRV_ACFGCAL_REG_INDEX(rst,##regi##)   ,\
                                                                                          ^~~~
make: *** [output/gcc_cortex_m3/simple/objs/main.c.o] Error 1

我为这些惊人数量的东西挤在一起道歉,但我们正在深度嵌入式环境中工作,我们需要为寄存器自动生成头文件而没有非常规则的布局(或命名约定)并尝试从他们身上做出一些东西。我们最终都试图让硬件看起来更加清醒。

我需要找到一种在GCC下“让它成功”的方法。关于我做错了什么的线索?我是否需要按摩我的宏(以及如何?)或者我是否需要刺激GCC以不同方式查看它们?

1 个答案:

答案 0 :(得分:0)

答案是一些编译器对预处理器可以与##运算符一起使用的内容更为宽松。

Visual Studio和Keil ARM编译器基本上允许将任何内容粘贴在一起; GCC只会粘贴“预处理器令牌”(不包括,.);在preprocessor tokens上进行网络搜索以找到比我更好的参考提供)。

外卖的教训是:如果你做了疯狂的宏观滥用,那么期待海湾合作委员会更加挑剔,并可能打破你想要做的事情。