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

veh*_*zzz 115 c gcc inline

假设我在源文件中有这个小功能

static void foo() {}
Run Code Online (Sandbox Code Playgroud)

我构建了二进制文件的优化版本,但我不希望这个函数内联(出于优化目的).我可以在源代码中添加一个宏来阻止内联吗?

ale*_*gle 137

您需要gcc-specific noinline属性.

此函数属性可防止将函数考虑为内联.如果函数没有副作用,那么除了内联之外,还有一些优化会导致函数调用被优化掉,尽管函数调用是实时的.为了防止此类调用被优化,请放置 asm ("");

像这样使用它:

void __attribute__ ((noinline)) foo() 
{
  ...
}
Run Code Online (Sandbox Code Playgroud)

  • 在Arch Linux上使用gcc 4.4.3,我得到了一个语法错误,其属性如上所示.它在函数之前正常工作(例如,__ attribute __((noinline))void foo(){}) (32认同)
  • Arduino也希望它放在功能之前. (2认同)
  • 编辑修复属性语法. (2认同)

luk*_*mac 28

GCC有一个名为的开关

-fno-inline-small-functions

所以在调用gcc时使用它.但副作用是所有其他小功能也是非内联的.


And*_*oss 21

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

void (*foo_ptr)() = foo;
foo_ptr();
Run Code Online (Sandbox Code Playgroud)

虽然这会产生不同的分支指令,但这可能不是你的目标.这带来了一个好点:你的目标什么?

  • 这在现代编译器上不起作用(例如 gcc 11、clang 12):它们会直接看到这一点并内联该函数:https://godbolt.org/z/hh8dcnE3v 添加“易失性”使其再次工作。 (4认同)
  • 如果指针是在文件范围内定义的,而不是静态的,那么它应该可以工作,因为编译器无法假设它在使用时具有其初始值。如果它是本地的(如图所示),它几乎肯定会被视为与 foo() 相同。(“在这十年中”,他补充说,看着日期) (2认同)

Sam*_*iao 13

如果您遇到编译器错误__attribute__((noinline)),您可以尝试:

noinline int func(int arg)
{
    ....
}
Run Code Online (Sandbox Code Playgroud)

  • 我收到一个错误:noinline没有命名类型. (2认同)

nem*_*equ 11

我知道问题是关于GCC,但我认为有关编译器其他编译器的一些信息也许有用.

GCC的 noinline 函数属性也很受其他编译器的欢迎.它至少得到以下支持:

  • Clang(检查__has_attribute(noinline))
  • 英特尔C/C++编译器(他们的文档非常糟糕,但我确信它适用于16.0+)
  • Oracle Solaris 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.英特尔也可能支持它(它们试图与GCC和MSVC兼容),但我没有费心去验证这一点.语法基本相同:

__declspec(noinline)
static void foo(void) { }
Run Code Online (Sandbox Code Playgroud)

PGI 10.2+(可能更旧)支持noinline适用于下一个函数的pragma:

#pragma noinline
static void foo(void) { }
Run Code Online (Sandbox Code Playgroud)

TI 6.0+支持 FUNC_CANNOT_INLINE pragma(烦人地)在C和C++中的工作方式不同.在C++中,它类似于PGI:

#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }
Run Code Online (Sandbox Code Playgroud)

但是,在C中,函数名称是必需的:

#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }
Run Code Online (Sandbox Code Playgroud)

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

#pragma _CRI inline_never foo
static void foo(void) { }
Run Code Online (Sandbox Code Playgroud)

Oracle开发人员Studio还支持编译这需要函数名,可以追溯到至少复地开发6,但要注意,它需要拿出的声明,即使在最新版本:

static void foo(void);
#pragma no_inline(foo)
Run Code Online (Sandbox Code Playgroud)

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

如果,OTOH,你可以选择适合大多数人的东西,那么你可以放弃一些更美观,不需要重复自己的东西.这就是我为Hedley采取的方法,当前版本的 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
Run Code Online (Sandbox Code Playgroud)

如果你不想使用Hedley(它是一个单独的公共域/ CC0标题),你可以毫不费力地转换版本检查宏,但不仅仅是我愿意放入☺.


小智 9

static __attribute__ ((noinline))  void foo()
{

}
Run Code Online (Sandbox Code Playgroud)

这对我有用.


Chr*_*utz 7

使用noinline 属性:

int func(int arg) __attribute__((noinline))
{
}
Run Code Online (Sandbox Code Playgroud)

在声明外部使用函数和编写函数时,您应该使用它.