This question already has answers here:
Evaluate preprocessor token before ## concatenation

(2 个回答)


3年前关闭。




我正在尝试使用 ## 预处理器运算符来确定要使用的女巫 GPIO。
这是我的代码:
#define GPIO_Pin_1 0x0001
#define GPIO_Pin_2 0x00CA
#define GPIO_Pin_3 0x00DE
#define GPIO_Pin_4 0x00AC

#define DIVIDE(a , b) ( (a) / (b) )
#define NUMBER_TO_GPIO(a) GPIO_Pin_##DIVIDE(a , 2)

int gpioNumber = 8;
int gpioAddress = NUMBER_TO_GPIO(gpioNumber);

gpioAddress 的期望值为 0x00AC (GPIO_Pin_4) 但编译器给出了这个错误: "GPIO_Pin_DIVIDE 隐式声明"。我想连接 GPIO_Pin_ 和 DIVIDE(a,b) 宏的结果

最佳答案

没有什么好的方法可以只用 CPP 来做你想做的事情。特别是因为您在运行时计算 GPIO 数量。

确保它在编译时直接替换的唯一方法是直接使用索引(您没有这样做)

将此视为 C 中的解决方案:

const long GPIO_PINS[] = { 0xFFFF, 0x0001, 0x00CA, 0x00DE, 0x00AC };
static inline long getGPIOAddr(int gpioAddress) {
    return GPIO_PINS[gpioAddress >> 1];
}

int main() {
    const int gpioNumber = 8;
    return getGPIOAddr(gpioNumber);
}

这是 gcc 的汇编输出(clang 给出了类似的结果):


    .file   "foo.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    movl    $172, %eax ; NOTICE THE OPTIMIZATION HERE!
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .globl  GPIO_PINS
    .section    .rodata
    .align 32
    .type   GPIO_PINS, @object
    .size   GPIO_PINS, 40
GPIO_PINS:
    .quad   65535
    .quad   1
    .quad   202
    .quad   222
    .quad   172
    .ident  "GCC: (GNU) 7.2.0"
    .section    .note.GNU-stack,"",@progbits

为了完整起见,这里是 clang :
    .file   "foo.c"
    .text
    .globl  main
    .align  16, 0x90
    .type   main,@function
main:                                   # @main
    .cfi_startproc
# BB#0:
    movl    $172, %eax
    ret
.Ltmp0:
    .size   main, .Ltmp0-main
    .cfi_endproc

    .type   GPIO_PINS,@object       # @GPIO_PINS
    .section    .rodata,"a",@progbits
    .globl  GPIO_PINS
    .align  16
GPIO_PINS:
    .quad   65535                   # 0xffff
    .quad   1                       # 0x1
    .quad   202                     # 0xca
    .quad   222                     # 0xde
    .quad   172                     # 0xac
    .size   GPIO_PINS, 40


    .ident  "clang version 3.4.2 (tags/RELEASE_34/dot2-final)"
    .section    ".note.GNU-stack","",@progbits

任何优秀的现代编译器都可以确定 gpioNumber 在特定 AST 期间不会更改,并且会正确替换常量。

所以不要试图超越编译器,它在优化方面比你好得多。

如果您对编译器在这方面的擅长程度感兴趣,我已经在 Godbolt 上加载了这段代码:

https://godbolt.org/g/EWjsHB

您可以深入了解代码的反汇编。那里的所有编译器都使用 -O 作为选项来优化这些东西。

关于c++ - 将 ## 预处理器运算符与另一个宏输出一起使用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48749778/

10-11 22:47
查看更多