是否可以强制函数不进行内联?

我想强制一个小函数不被编译为内联函数,即使它很简单。我认为这对于调试是有用的。有关键词吗?

56518 次浏览

许多编译器可以执行跨翻译单元内联。Visual Studio 已经拥有它五年了,我相信 GCC 现在可以做到这一点——尤其是在 OP 被标记为 Visual C + + 的情况下,他的编译器可以应付得来。

最简单的方法是获取函数的地址,然后对它执行一些非无意义的操作,比如调用它或将它传递给操作系统/外部库函数。编译器不能内联这种函数。

你为什么要这么做 IDK。

@ 评论:

如果 OP 非常非常需要这个,那么他可以将其编译为一个 lib 并静态地链接到它。

是否可以强制函数不进行内联?

我甚至不会尝试回答这个问题,因为除了下面列出的两个原因外,与这个问题无关。

内联基本上是

  1. 这种优化对你来说是透明的
  2. 允许在标题中定义函数而不会产生多重定义错误的方法

(有些人会改变这两者的顺序,但我坚持传统的顺序。)

除非你绝对需要在某个头部或者 B)中使用 定义函数,否则你就是在分析和优化一段代码,并且比编译器更清楚什么应该内联,什么不应该内联,否则内联对你来说应该是无关紧要的。
这当然不应该是一个问题,因为调试。您的调试器应该(在 VC 的情况下也是如此)为您处理这个问题。

您可以在头文件和 cpp 文件之间划分类实现。如果你把函数放在类定义之外,你的小函数就不会内联。

在 Visual Studio 2010中,__declspec(noinline)告诉编译器永远不要内联特定的成员函数,例如:

class X {
__declspec(noinline) int member_func() {
return 0;
}
};

编辑: 此外,当使用 /clr编译时,具有安全属性的函数从不内联(同样,这是特定于 VS2010的)。

不过,我认为它在调试时没有任何用处。

请记住,内联是相关的在 函数调用站点,同样的功能可以内联在某些情况下,而不是在其他。

如果你的函数在编译单元之外是可见的,那么即使它在 所有当前使用的位置是内联的,函数体对于任何想要稍后调用它的人(通过链接对象文件)仍然是可用的。

为了使调用站点不内联,可以使用指向函数的指针。

void (*f_ptr)(int); // pointer to function
volatile bool useMe = true; // disallow optimizations
if (useMe)
f_ptr = myFunc;
else
f_ptr = useOtherFunc;


f_ptr(42); // this will not be inlined

对于 VC + + ,__declspec(noinline) 。与手册页相反,它似乎适用于独立函数,而且我认为我从未将它用于成员函数。您可能——尽管注意到我从来没有——也想考虑使用优化标志,因此只有 inline函数被考虑用于内联,尽管这当然具有全局效应,并且可能不是您想要的效果。

用于 gcc 的 __attribute__((noinline)) (以及许多不太常用的支持 gcc 属性语法的编译器)。我必须承认,我觉得我从没用过这个,但它似乎就在那里。

(当然,这两种类型的注释放在不同的地方,所以构造两者都可以接受的代码有点烦人。)

我不确定它们是如何与 inline C + + 关键字相互作用的; 我只在调试时使用过它们(当我只是希望某个特定的非内联函数在优化后不要内联时)或者在检查生成的代码时使用过它们(我很困惑,因为随机的东西是内联的)。

简单: 不要让编译器看到函数的定义。那么它就不可能是内联的。当然,只有当它的 你的代码。

当涉及到调试第三方代码时... ... 是的,这将是有用的,特别是如果您可以远程删除第三方代码。任何调试过包含大量 share _ ptr 解引用的代码的人都知道我在说什么。

如果它是类的成员函数,则将其设置为虚函数。

[[gnu::noinline]]属性

我们还可以对非标准的 gnu::noinline属性使用 C + + 11属性说明符语法: https://en.cppreference.com/w/cpp/language/attributes

这只是一个时间问题,直到 gnu::部分被丢弃,一个未来的 C + + 标准给出一个标准化的 [[noinline]]: -)

Main.cpp

[[gnu::noinline]]
int my_func() {
return 1;
}


int main() {
return my_func();
}

编译和拆卸:

g++ -ggdb3 -O3 -o main.out -std=c++11 -Wall -Wextra -pedantic-errors main.cpp
gdb -batch -ex 'disassemble/r main' main.out

[[gnu::noinline]]:

   0x0000000000001040 <+0>:     f3 0f 1e fa     endbr64
0x0000000000001044 <+4>:     e9 f7 00 00 00  jmpq   0x1140 <my_func()>

没有 [[gnu::noinline]]:

   0x0000000000001040 <+0>:     f3 0f 1e fa     endbr64
0x0000000000001044 <+4>:     b8 01 00 00 00  mov    $0x1,%eax
0x0000000000001049 <+9>:     c3      retq

在 Ubuntu 19.10上测试。