如何告诉 gcc 不要内联函数?

假设我在源文件中有这个小函数

static void foo() {}

我建立了一个优化版本的二进制文件,但我不希望这个函数内联(为了优化的目的)。有没有一个宏,我可以添加到源代码,以防止内联?

145104 次浏览

使用 noinline 属性:

int func(int arg) __attribute__((noinline))
{
}

在为外部使用声明函数和编写函数时,您可能都应该使用它。

您需要特定于 gccnoinline属性。

此函数属性防止 被考虑的功能 如果函数没有 有副作用 除了内联以外的优化 使函数调用得到优化 尽管函数调用是 为了阻止这样的电话 优化,放置 asm ("");

像这样使用它:

void __attribute__ ((noinline)) foo()
{
...
}

一种可移植的方法是通过指针调用函数:

void (*foo_ptr)() = foo;
foo_ptr();

虽然这会产生不同的分支指令,这可能不是您的目标。这就提出了一个很好的观点: 你的目标是什么?

如果你得到一个 __attribute__((noinline))的编译器错误,你可以试试:

noinline int func(int arg)
{
....
}
static __attribute__ ((noinline))  void foo()
{


}

我就是这么做的。

海湾合作委员会有一个名为

-fno-inline-small-functions

所以在调用 gcc 时使用它,但是副作用是所有其他的小函数也是非内联的。

我用的是 GCC 7.2。我特别需要一个非内联的函数,因为它必须在库中实例化。我试了 __attribute__((noinline))的答案,以及 asm("")的答案。这两个问题都没有解决。

最后,我认为在函数中定义一个静态变量将迫使编译器在静态变量块中为它分配空间,并在第一次调用函数时为它发出初始化。

这是一种肮脏的把戏,但它的工作。

我知道这个问题是关于海湾合作委员会的,但我认为这可能有助于 也有一些关于编译器的其他编译器的信息。

海湾合作委员会 noinline 函数属性也很受其他编译器的欢迎 至少由以下人士支持:

  • 叮当(与 __has_attribute(noinline)核对)
  • 英特尔 C/C + + 编译器(他们的文档很糟糕,但我 确定它可以在16.0 + 上运行)
  • Sun Studio 至少回落至12.2
  • ARM C/C + + 编译器返回至少4.1
  • IBM XL C/C + + 回到至少10.1
  • TI 8.0 + (或7.3 + 加上—— gcc,它将定义 __TI_GNU_ATTRIBUTE_SUPPORT__)

此外,MSVC 支持 __declspec(noinline) 返回到 Visual Studio 7.1。 Intel 可能也支持它(他们试图 与海湾合作委员会和 MSVC 兼容) ,但我没有麻烦 语法基本上是一样的:

__declspec(noinline)
static void foo(void) { }

PGI 10.2 + (可能更早)支持 noinline杂注 应用于下一个函数:

#pragma noinline
static void foo(void) { }

TI 6.0 + 支持 FUNC_CANNOT_INLINE 在 C 和 C + + 中,它的工作方式不同,在 C + + 中,它类似于 PGI:

#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }

然而,在 C 语言中,函数名是必需的:

#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }

Cray 6.4 + (可能更早)采用了类似的方法,要求 函数名称:

#pragma _CRI inline_never foo
static void foo(void) { }

Oracle Developer Studio 还支持一个杂注,该杂注采用 函数名称,返回到至少 Forte Developer 的 href = “ https://docs.oracle.com/cd/E19059-01/fortec6u2/806-7984/806-7984.pdf”rel = “ noReferrer”> 6 , 但请注意,它需要来 之后的声明,即使在最近 版本:

static void foo(void);
#pragma no_inline(foo)

根据您的专注程度,您可以创建一个 可以在任何地方工作,但是需要将函数名称设置为 以及作为参数的声明。

如果 OTOH 你能接受对大多数人有效的方法, 你可以做一些更美观的东西 不需要重复自己,这就是方法 我已经采取了 海德利,其中 目前版本的 HEDLEY _ Never _ INLINE 看起来像:

#if \
HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
HEDLEY_TI_VERSION_CHECK(8,0,0) || \
(HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
#  define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
#  define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
#  define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

如果你不想使用 Hedley (它是一个单一的公共领域/CC0 头) ,你可以转换版本检查宏没有太多 努力,但更多的我愿意投入。