将 ## 预处理器运算符与另一个宏输出一起使用
using ## preprocessor operator with another macros output
我正在尝试使用 ## 预处理器运算符来确定要使用的 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 declared implicitly"。我想连接 GPIO_Pin_ 和 DIVIDE(a,b) 宏
的结果
##
连接符号。因此,你形成了一个未知的符号GPIO_Pin_DIVIDE
。
您可以做的是:
#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) (DIVIDE( GPIO_Pin_##a , 2))
int gpioAddress = NUMBER_TO_GPIO(4);
但我不确定这是否是你的意思。
如评论中所述,您的宏将不起作用。您可以使用数组:
const int GPIO_Pins[] = {
/*GPIO_Pin_1*/ 0x0001,
/*GPIO_Pin_2*/ 0x00CA,
/*GPIO_Pin_3*/ 0x00DE,
/*GPIO_Pin_4*/ 0x00AC
};
#define NUMBER_TO_GPIO(a) GPIO_Pins[(a) / 2 - 1]
当然是没有边界检查的问题
对于 C++,在编译时使用 constexpr 计算值。
static constexpr std::array<int, 4> Pins = { 0x01, 0x0A, 0xDE, 0xAC };
static constexpr int pin2(int a)
{
return Pins[a / 2];
}
没有什么好的方法可以仅使用 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 给出了类似的东西):
gcc -S -O foo.c
.file "foo.c"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
movl 2, %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 2, %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 上加载了这段代码:
您可以随心所欲地查看代码的反汇编。 所有 那里的编译器使用 -O 作为选项优化了这些东西。
我正在尝试使用 ## 预处理器运算符来确定要使用的 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 declared implicitly"。我想连接 GPIO_Pin_ 和 DIVIDE(a,b) 宏
的结果##
连接符号。因此,你形成了一个未知的符号GPIO_Pin_DIVIDE
。
您可以做的是:
#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) (DIVIDE( GPIO_Pin_##a , 2))
int gpioAddress = NUMBER_TO_GPIO(4);
但我不确定这是否是你的意思。
如评论中所述,您的宏将不起作用。您可以使用数组:
const int GPIO_Pins[] = {
/*GPIO_Pin_1*/ 0x0001,
/*GPIO_Pin_2*/ 0x00CA,
/*GPIO_Pin_3*/ 0x00DE,
/*GPIO_Pin_4*/ 0x00AC
};
#define NUMBER_TO_GPIO(a) GPIO_Pins[(a) / 2 - 1]
当然是没有边界检查的问题
对于 C++,在编译时使用 constexpr 计算值。
static constexpr std::array<int, 4> Pins = { 0x01, 0x0A, 0xDE, 0xAC };
static constexpr int pin2(int a)
{
return Pins[a / 2];
}
没有什么好的方法可以仅使用 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 给出了类似的东西):
gcc -S -O foo.c
.file "foo.c"
.text
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
movl 2, %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 2, %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 上加载了这段代码:
您可以随心所欲地查看代码的反汇编。 所有 那里的编译器使用 -O 作为选项优化了这些东西。