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

C++ Cortex-M4中按值传递对象为何生成更小汇编代码?

关于Cortex-M4上C++引用与值传递的汇编体积差异问题

我在Cortex-M4平台测试C++引用特性时发现,将函数参数从引用传递改为按值传递后,生成的汇编代码体积更小,且这个现象是在为Foo结构体添加更多成员后出现的。同时我还想了解引用是否能被编译器完全优化。以下是测试代码及汇编输出:

引用传递版本代码

struct Foo
{
    int x;
    int y;
    int bar[128];
    float f;
    float b;
    char hello;
    int * i;
};

Foo &getFoo(void)
{
    static Foo _f;
    return _f;
}

void passFoo(Foo& f)
{
    f.x = 0;
    return;
}

int main(void)
{
    Foo & f = getFoo();
    passFoo(f);
}

引用传递版本汇编输出

getFoo():
        ldr     r0, .L3
        bx      lr
.L3:
        .word   .LANCHOR0
passFoo(Foo&):
        movs    r3, #0
        str     r3, [r0]
        bx      lr
main:
        ldr     r3, .L7
        movs    r0, #0
        str     r0, [r3]
        bx      lr
.L7:
        .word   .LANCHOR0

按值传递版本代码

struct Foo
{
    int x;
    int y;
    int bar[128];
    float f;
    float b;
    char hello;
    int * i;
};

Foo &getFoo(void)
{
    static Foo _f;
    return _f;
}

void passFoo(Foo f)
{
    f.x = 0;
    return;
}

int main(void)
{
    Foo & f = getFoo();
    passFoo(f);
}

按值传递版本汇编输出

getFoo():
        ldr     r0, .L3
        bx      lr
.L3:
        .word   .LANCHOR0
passFoo(Foo):
        sub     sp, sp, #16
        stm     sp, {r0, r1, r2, r3}
        add     sp, sp, #16
        bx      lr
main:
        movs    r0, #0
        bx      lr

问题解答

1. 汇编体积差异的原因

  • 按值传递的死代码消除:按值传递版本中,passFoo修改的是传入的Foo副本,这个副本是局部变量,修改后没有任何后续使用(既不返回也不影响外部状态)。编译器直接触发了死代码消除优化:
    • main中原本需要拷贝整个大结构体到passFoo的参数,但因为passFoo的操作完全无意义,编译器直接删除了结构体拷贝和passFoo调用的所有相关代码,main仅保留最简的返回逻辑。
    • 而引用传递版本中,passFoo直接修改全局静态Foo的x成员,这个操作会改变外部可见状态,编译器无法消除该操作,因此main中必须保留对静态Foo地址的访问和赋值指令。
  • 结构体大小的触发条件:当Foo较小时,按值传递的拷贝操作开销不大,编译器可能不会做这么激进的消除;但当结构体足够大时,编译器更容易识别到“拷贝大结构体+无意义修改”的冗余性,从而彻底消除整个调用链的冗余代码,最终生成的代码比引用传递版本更短。

2. 引用能否被编译器完全优化

引用在C++标准中是对象的别名,底层通常由指针实现,但在很多场景下编译器可以做到完全优化:

  • 当引用的生命周期和指向对象的生命周期完全可被编译器追踪时(比如局部引用绑定到局部变量),编译器会直接把引用替换为原对象,不需要额外的指针操作。
  • 但如果引用跨函数传递(如作为函数参数),编译器需要遵守ABI约定传递指针(引用的底层实现);如果操作有副作用(比如修改外部对象),这些指针操作无法消除;如果没有副作用,可能会结合死代码消除等优化去掉冗余部分,但这不是引用本身的优化,而是整体代码的冗余消除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 01:15:39