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

裸机嵌入式C++使用-nostdlib编译时出现memcpy、memset未定义报错

问题原因

GCC在开启-O2优化时,会自动将连续内存拷贝、批量内存置零的循环逻辑,替换为更高效的memcpy/memset库函数调用,这就是你没有显式调用也触发未定义引用报错的根本原因,和头文件引入方式、名字修饰无关。你加了-nostdlib后没有链接标准库的实现,自然找不到这两个符号。

解决办法

按推荐优先级排序:

方案1:添加裸机编译选项(推荐,无需改代码)

在你的编译参数中添加-ffreestanding 以及对应内置函数禁用选项,直接禁止GCC自动替换内置函数:
你原来的编译指令修改为:

arm-none-eabi-g++ -c -mcpu=cortex-m4 -mthumb -std=c++11 -O2 -g -fno-exceptions -ffreestanding -fno-builtin-memcpy -fno-builtin-memset stm32_startup.cpp -o stm32_startup.o

-ffreestanding是裸机开发的标准编译选项,会告知GCC当前为无标准库的独立运行环境,不会默认假定main函数存在,也不会随意将循环替换为标准库函数调用。

方案2:自行实现memcpy和memset函数

如果不想改编译参数,可以直接在你的启动代码中添加这两个函数的极简实现,注意要加extern "C"避免C++名字修饰:
首先删除#include <string.h>,然后添加如下代码:

extern "C" void* memcpy(void* __restrict dest, const void* __restrict src, size_t n)
{
    uint8_t* d = static_cast<uint8_t*>(dest);
    const uint8_t* s = static_cast<const uint8_t*>(src);
    for (size_t i = 0; i < n; ++i) {
        d[i] = s[i];
    }
    return dest;
}

extern "C" void* memset(void* dest, int c, size_t n)
{
    uint8_t* d = static_cast<uint8_t*>(dest);
    const uint8_t val = static_cast<uint8_t>(c);
    for (size_t i = 0; i < n; ++i) {
        d[i] = val;
    }
    return dest;
}

这个实现完全满足你拷贝.data段、清.bss段的需求,不需要额外优化也能正常运行。

方案3:不要移除-nostdlib(不推荐)

你移除-nostdlib后报错是因为标准库默认的crt0启动代码需要你的链接脚本定义__bss_start__、__bss_end__等符号,还需要你实现_exit等系统调用存根,完全没必要。你自己已经实现了Reset_Handler作为入口,用-nostdlib才是裸机开发的正确选择。

额外建议

如果后续使用C++特性还要注意:

  • 如果你有全局/静态对象,需要在Reset_Handler调用main之前执行全局构造函数,需要在链接脚本里定义构造函数段的起止符号,然后遍历调用函数指针即可。
  • 编译参数建议始终保留-ffreestanding -fno-rtti -fno-exceptions,避免生成依赖标准库的代码。

内容的提问来源于stack exchange,提问作者Juan_David

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:45:02