首页 > 解决方案 > 嵌套预处理器等同于#define

问题描述

我正在尝试创建一个宏,将makefile中的#define create 转换为自动生成的#defines 列表,这些#defines 是外围组件的起始地址。这是测试代码:

#include <stdio.h>
#include <stdint.h>

/* Created by makefile to specify the core/CPU */
#define  CPU_ID       5

/* Autogenerated hardware register descriptors */
#define CPU0_PERIPHERAL_I2C_BASE__ADDR         (0x40000)
#define CPU1_PERIPHERAL_I2C_BASE__ADDR         (0x56000)
#define CPU2_PERIPHERAL_I2C_BASE__ADDR         (0x57000)
#define CPU3_PERIPHERAL_I2C_BASE__ADDR         (0x61000)
#define SUBCORE0_PERIPHERAL_I2C_BASE__ADDR     (0x67000)
#define SUBCORE1_PERIPHERAL_I2C_BASE__ADDR     (0x90000)
#define SUBCORE2_PERIPHERAL_I2C_BASE__ADDR     (0xA3000)
#define SUBCORE3_PERIPHERAL_I2C_BASE__ADDR     (0xE3000)

#define BASE_ADDR_DEF     _PERIPHERAL_I2C_BASE__ADDR

/* defines for translating CPU_ID into autogenerated hardware regs */
#define CPU_ID_0       "CPU0"
#define CPU_ID_1       "CPU1"
#define CPU_ID_2       "CPU2"
#define CPU_ID_3       "CPU3"
#define CPU_ID_4       "SUBCORE0"
#define CPU_ID_5       "SUBCORE1"
#define CPU_ID_6       "SUBCORE2"
#define CPU_ID_7       "SUBCORE3"

#define _JOIN(x,y)       x ## y
#define _DEF1(cpu_id)    _JOIN(CPU_ID_,cpu_id)
#define _DEF2(cpu_id)    _JOIN(_DEF1(cpu_id),BASE_ADDR_DEF)

int main(void)
{
    printf("%s\n", _DEF1(CPU_ID));  // <- this prints out "SUBCORE0" which is part of the way there
    printf("%X\n", _DEF2(CPU_ID));  // <- This will not compile
    return 0;
}

_DEF1 宏在输出中起作用,在这种情况下,如我所料,将是“SUBCORE1”。我似乎无法让宏翻译一个额外的级别以将“SUBCORE1”与“_PERIPHERAL_I2C_BASE__ADDR”组合以创建“SUBCORE1_PERIPHERAL_I2C_BASE__ADDR”,然后打印出应该是 0x90000 的十六进制值。在我没有看到或无法正确扩展的过程中,我是否错过了另一个级别的宏?

编辑:我知道人们在评论文字字符串,我知道这不是最终目标,但这只是试验时的许多迭代步骤之一。我只需要一些例子来展示我想要做什么。谢谢。

标签: cc-preprocessor

解决方案


  1. 将宏声明为不是字符串文字。就像弦一样。改变前。"SUBCORE3"SUBCORE3. 预处理器无法删除".
  2. 您需要使用嵌套宏触发扩展。前任。#define _JOIN2(x, y) x ## y进而#define _JOIN(x, y) _JOIN2(x, y)
  3. 所有以下划线后跟大字母的标识符都是标准保留的。声明它们是未定义的行为。

#include <stdio.h>
#include <stdint.h>

/* Created by makefile to specify the core/CPU */
#define  CPU_ID       5

/* Autogenerated hardware register descriptors */
#define CPU0_PERIPHERAL_I2C_BASE__ADDR         (0x40000)
#define CPU1_PERIPHERAL_I2C_BASE__ADDR         (0x56000)
#define CPU2_PERIPHERAL_I2C_BASE__ADDR         (0x57000)
#define CPU3_PERIPHERAL_I2C_BASE__ADDR         (0x61000)
#define SUBCORE0_PERIPHERAL_I2C_BASE__ADDR     (0x67000)
#define SUBCORE1_PERIPHERAL_I2C_BASE__ADDR     (0x90000)
#define SUBCORE2_PERIPHERAL_I2C_BASE__ADDR     (0xA3000)
#define SUBCORE3_PERIPHERAL_I2C_BASE__ADDR     (0xE3000)

#define BASE_ADDR_DEF     _PERIPHERAL_I2C_BASE__ADDR

/* defines for translating CPU_ID into autogenerated hardware regs */
#define CPU_ID_0       CPU0
#define CPU_ID_1       CPU1
#define CPU_ID_2       CPU2
#define CPU_ID_3       CPU3
#define CPU_ID_4       SUBCORE0
#define CPU_ID_5       SUBCORE1
#define CPU_ID_6       SUBCORE2
#define CPU_ID_7       SUBCORE3

// usually those are called CONCAT or CONCATX or CONCAT2 or XCONCAT etc.
// so I name them the same here
// XCONCAT is a mnemonic from "eXpand then CONCATenate"
#define CONCAT(x,y)     x ## y
#define XCONCAT(x,y)    CONCAT(x, y)
#define STRING(x)        #x
#define XSTRING(x)       STRING(x)
// note that glibc defines __CONCAT __XCONCAT __STRING __XSTRING

// trigger the expansions
#define DEF1(cpu_id)    XCONCAT(CPU_ID_, cpu_id)
#define DEF2(cpu_id)    XCONCAT(DEF1(cpu_id),BASE_ADDR_DEF)

int main(void)
{
    printf("%s\n", XSTRING(DEF1(CPU_ID)));  // <- this prints out "SUBCORE0", which is at all not part the way here
    printf("%X\n", DEF2(CPU_ID));  // <- This will expand to 0x90000
    return 0;
}

推荐阅读