函数仅在标题中定义时才会内联.我错过了什么吗?

Mik*_*ike 3 c c++ g++ inline compiler-optimization

使用gcc v4.8.1

如果我做:

//func.hpp

#ifndef FUNC_HPP
#define FUNC_HPP

int func(int);

#endif

//func.cpp

#include "func.hpp"

int func(int x){
    return 5*x+7;
}

//main.cpp

#include <iostream>

#include "func.hpp"

using std::cout;
using std::endl;

int main(){
    cout<<func(5)<<endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

即使是简单的功能func也不会内联.无相结合inline,extern,static,并__attribute__((always_inline))在样机和/或定义改变了这种(这些说明的一些明显的组合,导致它甚至不会编译和/或产生警告,不谈论那些).我正在使用g++ *.cpp -O3 -o rung++ *.cpp -O3 -S组装输出.当我看到装配输出时,我仍然看到call func.它似乎只有我能够正确内联函数的方法是拥有原型(可能没有必要)和头文件中函数的定义.如果标题只包含在整个程序中的一个文件中(仅main.cpp作为例子包含),它将编译并且函数将被正确内联,甚至不需要inline符.如果要将标头包含在多个文件中,则inline需要使用说明符来解决多个定义错误,这似乎是其唯一目的.该功能当然可以正确内联.

所以我的问题是:我做错了吗?我错过了什么吗?无论发生什么:

"编译器比你聪明.它知道什么时候应该比你更好地内联函数.永远不要使用C数组.总是使用std :: vector!"

- 每个其他StackOverflow用户

真?所以调用func(5)并打印结果比打印32更快?我会盲目地跟着你离开悬崖的边缘所有人都知道并且所有明智的gcc.

为了记录,上面的代码只是一个例子.我正在写一个光线跟踪器,当我将我的数学和其他实用程序类的所有代码移动到它们的头文件并使用说明inline符时,我看到了大量的性能提升.对于某些场景,字面意思快10倍.

Bas*_*tch 7

最近的GCC能够通过链接时优化(LTO)内联编译单元.你需要编译 - 和链接 - -flto; 请参阅链接时优化和内联GCC优化选项.

(实际上,LTO是lto1在链接时由编译器的特殊变体完成的; LTO通过在目标文件内部序列化,GCC的一些内部表示,也被使用lto1;因此-flto,当src1.c使用它编译a时会发生什么?所生成的src1.o含有除该对象的二进制的GIMPLE表示;以及当连接gcc -flto src*.olto1"前端"是提取那个GIMPLE表示从内侧src*.o和几乎再次重新编译所有...)

您需要-flto在编译时和链接时显式传递它们(请参阅此内容).如果使用Makefile你可以尝试make CC='gcc -flto'; 否则,用例如gcc -Wall -flto -O2 -c src1.c(和同样的src2.c等等)编译每个翻译单元并链接你的所有程序(或库)gcc -Wall -flto -O2 src1.o src2.o -o prog -lsomelib

请注意,这-flto将显着减慢您的构建速度(它不会被传递,-O3因此您需要明确地使用它,并且您还需要与它链接).通常,您可以将构建程序的性能提高5%或10%,但代价是构建时间几乎翻倍.有时您可以获得更多改进.

  • @Mike 您现在可能已经发现了自己,但答案是否定的。必须显式调用链接时优化。 (2认同)