为什么 MSVC 编译器将模板实例化二进制文件放入程序集中?

Why does MSVC compiler put template instantiation binaries in assembly?

我在 MSVC 编译器中遇到了一些奇怪的事情。

它将函数模板定义放在汇编中,而优化消除了对它们的需要。 Clang 和 GCC 似乎完全成功地删除了函数定义,但 MSVC 没有。

能修好吗?

main.cpp:

#include <iostream>

template <int n> int value() noexcept
{
    return n;
}

int main()
{
    return value<5>() + value<10>();
}

程序集:

int value<5>(void) PROC                                ; value<5>, COMDAT
        mov     eax, 5
        ret     0
int value<5>(void) ENDP                                ; value<5>

int value<10>(void) PROC                                ; value<10>, COMDAT
        mov     eax, 10
        ret     0
int value<10>(void) ENDP                                ; value<10>

main    PROC                                            ; COMDAT
        mov     eax, 15
        ret     0
main    ENDP

Sample code on godbolt

/FA 开关为每个翻译单元生成列表文件。由于这是 before 链接阶段,MSVC 无法确定程序中其他任何地方是否需要这两个函数,因此仍包含在生成的 .asm 文件中(注意:这可能对 MS 来说是为了简单起见,因为它可以将模板视为与生成的 .obj 文件中的常规函数​​相同,但实际上没有实际需要将它们存储在 .obj 文件中,正如 user17732522 在评论中指出的那样)。

在链接过程中,MSVC 确定这些函数实际上并没有在其他任何地方实际使用/需要,因此可以删除(即使它们在其他地方使用过,因为结果可以在编译时确定,它们会仍然被删除)从编译的可执行文件中。

为了查看最终编译的可执行文件中的内容,您可以通过反汇编程序查看可执行文件。使用 MSVC 执行此操作的示例是在主函数中放置一个断点,运行 它,然后当断点被击中时,右键单击并“查看反汇编”。在这里,你会看到这两个函数已经不存在了。

您也可以使用 /MAP 选项生成 Mapfile,这也表明它不存在。


If 我正确地阅读了 documentation,似乎那些 MS 选择包含模板 类 和函数的显式实例化,因为它“是在创建库时很有用”。不过,未实例化的模板不会放入 obj 文件中。

只需将 /Zc:inline 添加到您的编译语句,如果您 将模板包装在匿名命名空间中以确保它与 clang/GCC 做同样的事情它没有外部可见性。

#include <iostream>

namespace
{
    template <int n> int value() noexcept
    {
        return n;
    }
}

或者如果你标记模板函数inline

template <int n> inline int value() noexcept
{
    return n;
}

两者都导致:

main    PROC
        mov     eax, 15
        ret     0
main    ENDP

/Zc:inline (删除未引用的 COMDAT) 开关已添加到 VS 2015 Update 2 中,作为 C++11 标准一致性的一部分,允许此优化。

在 command-line 版本中是 off-by-default。在 MSBuild 中,<RemoveUnreferencedCodeData> 默认为 true。

Microsoft Docs

OTHERWISE 它将在链接器阶段用 /OPT:REF 清除。

我在我的 vs2022 上以发布模式编译了你的代码。我得到

    return value<5>() + value<10>();
00007FF65CD21000  mov         eax,0Fh  
}
00007FF65CD21005  ret