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

C++中-O3编译下,指针与引用参数函数是否生成不同汇编?

C++指针与引用作为函数参数的汇编差异

在-O3等高级优化编译下,多数场景中指针和引用作为函数参数会生成完全一致的汇编代码,就像你给出的测试示例:

你的测试示例

结构体定义

struct someStruct
{
    int a;
    int* ptr;
    someStruct* next;
};

指针版本函数

int f1(someStruct* v)
{
    v->a = v->next->a + *v->next->ptr;
    v->ptr = v->next->ptr;
    v->next = v;
    return v->a;
}

引用版本函数

int f1(someStruct& v)
{
    v.a = v.next->a + *v.next->ptr;
    v.ptr = v.next->ptr;
    v.next = &v;
    return v.a;
}

生成的汇编代码(二者完全一致)

f1(someS*):                           # @f1(someS*)
        mov     rcx, qword ptr [rdi + 16]
        mov     rdx, qword ptr [rcx + 8]
        mov     eax, dword ptr [rdx]
        add     eax, dword ptr [rcx]
        mov     dword ptr [rdi], eax
        mov     qword ptr [rdi + 8], rdx
        mov     qword ptr [rdi + 16], rdi
        ret

但确实存在一些例外场景,指针和引用作为参数会生成不同的汇编代码,以下是几种典型情况:


1. 空指针检查场景

C++标准要求引用必须绑定到有效对象,编译器可以假设引用永远不为空;但指针可能为空,若代码中显式检查空指针,编译器会保留相关逻辑。

示例代码

// 指针版本:显式检查空指针
int func_ptr(someStruct* v) {
    if (!v) return -1;
    return v->a;
}

// 引用版本:无需(也不能)检查引用是否为空
int func_ref(someStruct& v) {
    return v.a;
}

汇编差异(GCC -O3为例)

指针版本汇编包含空指针判断逻辑:

func_ptr(someStruct*):
        test    rdi, rdi
        je      .L3
        mov     eax, DWORD PTR [rdi]
        ret
.L3:
        mov     eax, -1
        ret

引用版本汇编直接访问对象,无检查步骤:

func_ref(someStruct&):
        mov     eax, DWORD PTR [rdi]
        ret

2. 指针可重新赋值,引用不可

引用是对象的别名,一旦绑定就无法重新指向其他对象;指针则可以被重新赋值。这种语义差异会直接导致汇编不同。

示例代码

void func_ptr(someStruct* v, someStruct* other) {
    v = other; // 重新赋值指针指向
    v->a = 10;
}

void func_ref(someStruct& v, someStruct& other) {
    v = other; // 仅拷贝other的内容到v绑定的对象,而非改变引用指向
}

汇编差异(GCC -O3)

指针版本汇编直接修改other指向对象的a成员(编译器优化后等价于直接操作目标地址):

func_ptr(someStruct*, someStruct*):
        mov     DWORD PTR [rsi], 10
        ret

引用版本汇编则是将other的所有成员拷贝到v绑定的对象内存中:

func_ref(someStruct&, someStruct&):
        mov     rax, QWORD PTR [rsi+8]
        mov     edx, DWORD PTR [rsi]
        mov     QWORD PTR [rdi+8], rax
        mov     rcx, QWORD PTR [rsi+16]
        mov     DWORD PTR [rdi], edx
        mov     QWORD PTR [rdi+16], rcx
        ret

3. 取地址操作的语义差异

对指针取地址得到的是指针变量自身的地址;对引用取地址得到的是绑定对象的地址,这种本质差异会导致汇编不同。

示例代码

// 指针版本:返回指针变量自身的地址
someStruct** get_ptr_addr(someStruct* v) {
    return &v;
}

// 引用版本:返回引用绑定对象的地址
someStruct* get_ref_addr(someStruct& v) {
    return &v;
}

汇编差异(GCC -O3)

指针版本汇编返回栈上指针变量的地址:

get_ptr_addr(someStruct*):
        lea     rax, [rsp+8]
        ret

引用版本汇编直接返回传入的对象地址(即函数参数寄存器rdi的值):

get_ref_addr(someStruct&):
        mov     rax, rdi
        ret

总结

在语义完全等价的场景下,编译器通常会将引用优化为与指针相同的汇编实现;但当二者的核心语义(如空指针合法性、可赋值性、取地址行为)存在差异时,生成的汇编代码就会出现明显不同。

内容的提问来源于stack exchange,提问作者Egemen Yalın

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:33:27