与包含复杂函数的内联

Inline with containing complex function

本文关键字:函数 包含 复杂      更新时间:2023-10-16

让我们举个例子:

Class TestClass {
public:
  int functionInline();
  int functionComplex();
};
inline int TestClas::functionInline()
{
  // a single instruction
  return functionComplex();
}
int TestClas::functionComplex()
{
  /* many complex
     instructions
  */
}
void myFunc()
{
  TestClass testVar;
  testVar.functionInline();
}

假设所有的coment实际上都是单行或多行复杂代码的代码行。等效代码为(编译后):

void myFunc()
{
  TestClass testVar;
  // a single instruction
  return functionComplex();
}

或者是:

void myFunc()
{
  TestClass testVar;
  // a single instruction
  /* many complex
     instructions
  */
}

换句话说,如果在内联函数内部调用一个普通函数,它是否会内联插入?

如果编译器可以看到函数在其他地方没有被调用(例如,在自由函数的情况下,它是static),那么至少gcc已经内联了它很长一段时间。

当然,这也假设编译器实际上可以"看到"函数的源代码——只有当你使用"整个程序优化"(至少在MS和GCC编译器中可用)时,它才能内联不在源文件或源中包含的头文件中的函数。

显然,内联一个"大"函数没有什么好处(因为进行调用的开销在整个运行时中只占很小的一部分),如果该函数被多次调用(或者由于不是static而"可能被多次调用"),编译器几乎肯定不会内联一个"大"函数。

总之:也许大型函数是内联的,但很可能不是。

请检查我为VC++2010和g++生成的汇编代码。在本例中,两个编译器实际上都没有将任何函数视为内联函数。

代码:

class TestClass {
public:
  int functionInline();
  int functionComplex();
};
inline int TestClass::functionInline()
{
  // a single instruction
  return functionComplex();
}
int TestClass::functionComplex()
{
  /* many complex
     instructions
  */
    return 0;
}
int main(){
    TestClass t;
    t.functionInline();
    return 0;
}

VC++2010:

int main(){
01372E50  push        ebp  
01372E51  mov         ebp,esp  
01372E53  sub         esp,0CCh  
01372E59  push        ebx  
01372E5A  push        esi  
01372E5B  push        edi  
01372E5C  lea         edi,[ebp-0CCh]  
01372E62  mov         ecx,33h  
01372E67  mov         eax,0CCCCCCCCh  
01372E6C  rep stos    dword ptr es:[edi]  
    TestClass t;
    t.functionInline();
01372E6E  lea         ecx,[t]  
01372E71  call        TestClass::functionInline (1371677h)  
    return 0;
01372E76  xor         eax,eax  
}

Linux G++:

main:
.LFB3:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    leaq    -1(%rbp), %rax
    movq    %rax, %rdi
    call    _ZN9TestClass14functionInlineEv
    movl    $0, %eax
    leave
    ret
    .cfi_endproc

两条线路

01372E71调用TestClass::functionInline(1371677h)

调用_ZN9TestClass14函数InlineEv

指示函数functionInline不是内联的。

现在看看函数内联汇编:

inline int TestClass::functionInline()
{
01372E00  push        ebp  
01372E01  mov         ebp,esp  
01372E03  sub         esp,0CCh  
01372E09  push        ebx  
01372E0A  push        esi  
01372E0B  push        edi  
01372E0C  push        ecx  
01372E0D  lea         edi,[ebp-0CCh]  
01372E13  mov         ecx,33h  
01372E18  mov         eax,0CCCCCCCCh  
01372E1D  rep stos    dword ptr es:[edi]  
01372E1F  pop         ecx  
01372E20  mov         dword ptr [ebp-8],ecx  
  // a single instruction
  return functionComplex();
01372E23  mov         ecx,dword ptr [this]  
01372E26  call        TestClass::functionComplex (1371627h)  
}

因此,函数Complex也不是内联的。

不,它不会被内联。这是不可能的,因为编译器没有可能位于另一个翻译单元中的非内联函数的主体定义。我认为普通函数是一个非内联函数。

,如果您希望以内联方式插入复杂函数,则还必须指定inline关键字
在实践中,使用__forceinline关键字(在windows上,__always_inline在linux上),否则如果有很多指令,编译器将忽略该关键字。

首先,内联函数只是编译器的一个指令。不能保证编译器会执行内联。

其次,当您指定一个函数为内联时,它会告诉编译器两件事

1) 函数可能是内联的候选者。不能保证它是否会被内联2) 此功能具有内部链接。也就是说,函数只有在编译的翻译单元中才可见。无论函数是否实际内联,都可以保证这种内部链接。

在您的情况下,functionInline被指定为inline,但functionComplex不是。functionComplex具有外部链接。编译器永远不会对具有外部链接的函数进行内联。

因此,您的问题的简单答案是"否"。一个正常的(没有内联关键字并在类外定义的函数)函数永远不会内联