c++ - 内联函数编译

标签 c++ compilation inline one-definition-rule header-only

我打算为操作系统 API 提供简单的包装器,它会在发生错误时抛出异常。这些包装器很简单,并且都被定义为头文件中的内联函数。由于系统 API 应该很大,头文件也应该很大,包含大量微小的内联函数。问题是,如果共享库 (.so) 是在包含头文件的情况下编译的,那么所有这些微小的包装器是否都会被编译到生成的二进制文件中,从而产生一个大的二进制文件,即使实际上只有一小部分包装器是用过的?可执行文件的情况会有所不同吗?如果是这样,将包装器拆分为多个头文件是否是唯一的解决方案?或者我应该通过指定 static 使包装器内部链接?

这是我的想法。包装器可能会被 ODR 使用(例如,获取其地址)。在 Linux 平台上,默认导出具有外部链接的函数(即,可由其他二进制模块链接)。所以我想链接器可能有必要为它们实际生成大纲定义。请参阅描述部分中的要点 3) here .

在 Windows API 中包装 CloseHandle() 的简单示例:

inline void close_handle(HANDLE handle) {
  if (!CloseHandle(handle)) {
    throw std::system_error(GetLastError(), std::system_category(), "CloseHandle");
  }
}

最佳答案

声明为 static inline 的(相当小的)函数(或者通常只是 inline ,或者甚至是定义在 inside 某些 classstruct 中的成员函数)将不会(在实践中)出现在代码中,如果它未使用(请参阅 this ),并且可能会在任何地方内联。当然,您需要在编译命令中启用优化。因此,如果使用 GCC ,则使用 g++ -Wall -O2 进行编译(您可以添加 -fverbose-asm -S 并查看生成的汇编代码以进行检查)。

一些编译器(可能还有 g++ )如果不被要求优化则不会打扰内联。内联始终是一种优化,编译器在某些情况下可能不会这样做(特别是在某处存储该函数的地址时)

顺便说一句,看起来您正在重新发明一个类似于 POCOQt 的框架。您是否考虑过改用它们?

此外,最近的 C++11(和 C++14)实现已经包装了操作系统 API 的重要部分(特别是标准 C++ IO library 和 C++ thread support library 以及最近的 C++14 TS ),通常已经使用异常,因此更好地利用它们并使用最新 C++ 编译器(对于 GCC,这意味着 2015 年 11 月的 GCC 5.2)。

(换句话说,至少为 C++11 编写代码,而不是 C++98)

在带有 GCC(或 Clang/LLVM)的 Linux 上,如果创建一个库,您可能对链接时间优化(编译并链接带有 g++ -O2 -flto 的库)、precompiled headersvisibility 函数 attributes 感兴趣。

关于 Linux 上的程序库,阅读 Program Library HowTo 。对于共享库,请阅读 Drepper 的论文:How to Write Shared Librariesthis 答案。

在实践中,一些库中的内联函数通常不会在库中概述,而是在调用它的应用程序中。因此,如果您的共享库 Foo 在公共(public) header <foo.h> 中定义

 inline int maxsq(int a, int b) {
    // you could add some conditional throw here...
    if (std::abs(a) < std::abs(b)) return b*b;
    else return a*a;
 }

那么 maxsq 的目标代码可能不会出现在 libfoo.so 中,但如果该程序需要概述 #include <foo.h>,则只会出现在您的程序(其源代码中为 maxsq)中,例如将 maxsq 的地址存储在某处(或者如果您没有要求足够的优化)。

请记住,内联始终是一种优化,某些编译器有时可能会避免它(即使出于良好的性能原因)。在实践中,相信您的编译器(实际上,您的 C++ 实现还包括链接器,它可能会“收集垃圾”sections)。

关于c++ - 内联函数编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33734341/

相关文章:

java - typescript 编译(就Java编译而言)

javascript - HTML 中的内联 Javascript 无法加载

generics - F# 泛型类型约束和鸭子类型

javascript - 如何读取元素的内联样式?

c++ - 函数指针的分支预测

c++ - MFC 添加项目到系统菜单

c++ - 没有匹配函数调用 ‘begin(int**&)’

javascript - 哪个浏览器率先推出了 JIT 编译的 JavaScript?

c++ - 返回错误答案的简单 C++ 二次方程求解器

c++ - 在没有 'thread management' 的 C++ 中并发哈希表/哈希集?