You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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:分离头文件声明与库默认实现

将弱定义的别名实现放在库文件中,头文件仅提供无属性的函数声明,避免用户代码与库定义冲突:

  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
};
  1. 头文件(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
  1. 用户代码(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:07:24