在 C++ 中返回一个空类与不返回任何内容(void)是一样的吗?

分享于2022年10月08日 assembly c++ optimization 问答
【问题标题】:Is returning an empty class in C++ is the same as returning nothing (void)?在 C++ 中返回一个空类与不返回任何内容(void)是一样的吗?
【发布时间】:2022-10-07 16:29:23
【问题描述】:

我想知道如果我返回一个空的、无成员的类/结构与什么都不返回(如在 void -declared 函数中),在性能方面是否相同。

struct nothing {};

void func1()
{
};

nothing func2()
{
     return nothing{};
};

int main()
{
    func1();
    nothing n = func2();
}

这些对 func1 和 func2 的调用实际上会在现代编译器上产生相同的汇编输出吗?


【解决方案1】:

因此,我正在使用如下命令在 clang 14.0.6 上对此进行调查:

clang++ -O0 -S -masm=intel test.cpp

func1 结果:

    .globl  "?func1@@YAXXZ"                 # -- Begin function ?func1@@YAXXZ
    .p2align    4, 0x90
"?func1@@YAXXZ":                        # @"?func1@@YAXXZ"
# %bb.0:
    ret
                                        # -- End function

虽然 func2 导致:

    .globl  "?func2@@YA?AUnothing@@XZ"      # -- Begin function ?func2@@YA?AUnothing@@XZ
    .p2align    4, 0x90
"?func2@@YA?AUnothing@@XZ":             # @"?func2@@YA?AUnothing@@XZ"
.seh_proc "?func2@@YA?AUnothing@@XZ"
# %bb.0:
    push    rax
    .seh_stackalloc 8
    .seh_endprologue
    mov al, byte ptr [rsp]
    pop rcx
    ret
    .seh_endproc
                                        # -- End function

主要看起来是这样的(见注释行):

main:                                   # @main
.seh_proc main
# %bb.0:
    sub rsp, 40
    .seh_stackalloc 40
    .seh_endprologue
    call    "?func1@@YAXXZ"
    call    "?func2@@YA?AUnothing@@XZ"
    mov byte ptr [rsp + 32], al         # -- This line is also a cost of 'nothing'
    xor eax, eax
    add rsp, 40
    ret
    .seh_endproc
                                        # -- End function

我们实际上可以在这里看到一些预期的差异,因为空结构/类在 C++ 中实际上是 1 字节的长度,也可能需要额外的调试时指令来执行。

然而,重要的是看看这是否会得到适当的优化,所以继续:

clang++ -O1 -S -masm=intel test.cpp

这次功能看起来相同:

    .globl  "?func1@@YAXXZ"                 # -- Begin function ?func1@@YAXXZ
    .p2align    4, 0x90
"?func1@@YAXXZ":                        # @"?func1@@YAXXZ"
# %bb.0:
    ret
                                        # -- End function

    .globl  "?func2@@YA?AUnothing@@XZ"      # -- Begin function ?func2@@YA?AUnothing@@XZ
    .p2align    4, 0x90
"?func2@@YA?AUnothing@@XZ":             # @"?func2@@YA?AUnothing@@XZ"
# %bb.0:
    ret
                                        # -- End function

由于调用没有有意义的副作用, main 显然被清除了:

main:                                   # @main
# %bb.0:
    xor eax, eax
    ret
                                        # -- End function

我们显然可以添加一些更复杂的逻辑,但是这次,我对在我当前有问题的范围内的结果感到满意,即,对于一个简单的内联可见范围,不返回任何内容与“返回”void 相同。

【讨论】:

  • -O0 确实没有回答问题中的“在性能方面”。