在C中重写弱函数时遭遇“error: redefinition”错误的技术问询
RV32EC架构CH32V003中断向量表重定义问题解决
问题背景
为RV32EC架构的CH32V003单片机编写C库代码,实现类似ARM Cortex-M的中断向量表(函数指针数组):未指定自定义处理函数时,弱定义指向默认处理函数;用户定义同名函数时自动覆盖默认项。但尝试重写默认函数时,出现error: redefinition编译错误。使用工具链为MacOS Sonoma下的xpack-riscv-none-elf-gcc-13.2.0-2。
现有代码
// system vectors // these are function prototypes that are supposed to be in the main.h header file __attribute__ ((weak, interrupt)) void system_vector_default(void); // reserved slot(s) in system vector table __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_NMI(void); // non-maskable interrupt handler __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_HardFault(void); // hard fault handler __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_SysTick(void); // SysTick interrupt handler __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_SW(void); // software interrupt void system_vector_default(void) { // reserved slot(s) in system vector table // note: this definition is required, as all the other weakly-linked functions point to it } void system_vector_NMI(void) {} // non-maskable interrupt handler //void system_vector_HardFault(void) {} // hard fault handler //void system_vector_SysTick(void) {} // SysTick interrupt handler //void system_vector_SW(void) {} // software interrupt __attribute__ ((section(".system_vector"))) void (* const system_vector_table[]) (void) = { // system vector table, skipping vector 0 (reserved) system_vector_default, // 1 - reserved system_vector_NMI, // 2 - non-maskable interrupt handler system_vector_HardFault, // 3 - hard fault interrupt handler system_vector_default, // 4 - reserved system_vector_default, // 5 - reserved system_vector_default, // 6 - reserved system_vector_default, // 7 - reserved system_vector_default, // 8 - reserved system_vector_default, // 9 - reserved system_vector_default, // 10 - reserved system_vector_default, // 11 - reserved system_vector_SysTick, // 12 - SysTick interrupt handler system_vector_default, // 13 - reserved system_vector_SW, // 14 - software interrupt handler system_vector_default, // 15 - reserved };
仅保留system_vector_default()定义时编译正常,向量表全部指向默认函数;但取消注释system_vector_NMI()等函数定义时触发错误。
错误信息
main.c:22:6: error: redefinition of 'system_vector_NMI' 22 | void system_vector_NMI(void) {} // non-maskable interrupt handler | ^~~~~~~~~~~~~~~~~ main.c:12:72: note: previous definition of 'system_vector_NMI' with type 'void(void)' 12 | __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_NMI(void); // non-maskable interrupt handler | ^~~~~~~~~~~~~~~~~ make: *** [J4-weak.elf] Error 1
问题原因
GCC中,当函数声明同时带有alias属性时,该声明会被编译器视为符号定义(别名定义),而非单纯的函数原型。后续用户编写的函数体属于第二次定义同一个符号,因此触发重定义错误。
解决方法
方案1:分离头文件声明与库默认实现
将弱定义的别名实现放在库文件中,头文件仅提供无属性的函数声明,避免用户代码与库定义冲突:
- 库文件(vector.c):
#include "vector.h" __attribute__ ((interrupt)) void system_vector_default(void) { // 默认中断处理逻辑 } // 为各中断函数定义弱别名,指向默认处理函数 __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_NMI(void); __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_HardFault(void); __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_SysTick(void); __attribute__ ((weak, interrupt, alias("system_vector_default"))) void system_vector_SW(void); // 定义向量表 __attribute__ ((section(".system_vector"))) void (* const system_vector_table[]) (void) = { system_vector_default, // 1 - reserved system_vector_NMI, // 2 - non-maskable interrupt handler system_vector_HardFault, // 3 - hard fault interrupt handler system_vector_default, // 4 - reserved system_vector_default, // 5 - reserved system_vector_default, // 6 - reserved system_vector_default, // 7 - reserved system_vector_default, // 8 - reserved system_vector_default, // 9 - reserved system_vector_default, // 10 - reserved system_vector_default, // 11 - reserved system_vector_SysTick, // 12 - SysTick interrupt handler system_vector_default, // 13 - reserved system_vector_SW, // 14 - software interrupt handler system_vector_default, // 15 - reserved };
- 头文件(vector.h):
#ifndef VECTOR_H #define VECTOR_H // 仅声明函数,不带任何属性 void system_vector_NMI(void); void system_vector_HardFault(void); void system_vector_SysTick(void); void system_vector_SW(void); // 声明向量表 extern void (* const system_vector_table[])(void); #endif
- 用户代码(main.c):
直接定义自定义处理函数即可,无需额外声明:
#include "vector.h" // 自定义NMI处理函数,自动覆盖库中的弱定义 void system_vector_NMI(void) { // 用户自定义逻辑 } int main(void) { // 主程序逻辑 while(1); }
方案2:拆分声明与别名定义
将函数的weak声明与alias定义分开,避免声明被当作符号定义:
修改原代码中的声明与默认实现部分:
// 仅带weak和interrupt属性的函数声明,无alias __attribute__ ((weak, interrupt)) void system_vector_default(void); __attribute__ ((weak, interrupt)) void system_vector_NMI(void); __attribute__ ((weak, interrupt)) void system_vector_HardFault(void); __attribute__ ((weak, interrupt)) void system_vector_SysTick(void); __attribute__ ((weak, interrupt)) void system_vector_SW(void); // 默认处理函数实现 void system_vector_default(void) { // 默认处理逻辑 } // 单独为各中断函数定义别名,指向默认处理函数 void system_vector_NMI(void) __attribute__((alias("system_vector_default"))); void system_vector_HardFault(void) __attribute__((alias("system_vector_default"))); void system_vector_SysTick(void) __attribute__((alias("system_vector_default"))); void system_vector_SW(void) __attribute__((alias("system_vector_default"))); // 向量表定义保持不变 __attribute__ ((section(".system_vector"))) void (* const system_vector_table[]) (void) = { // ... 原向量表内容 ... };
这样用户定义system_vector_NMI()时,会覆盖弱声明的符号,不会触发重定义错误。
内容的提问来源于stack exchange,提问作者Dale Wheat
相关产品推荐
相关产品推荐

