内联含有复杂功能

时间:2013-08-14 08:57:54

标签: c++ inline

我们以此为例:

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();
}

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

void myFunc()
{
  TestClass testVar;

  // a single instruction
  return functionComplex();
}

或将是:

void myFunc()
{
  TestClass testVar;

  // a single instruction

  /* many complex
     instructions
  */
}

换句话说,如果在内联函数内部调用,是否会将内联函数插入内联?

5 个答案:

答案 0 :(得分:1)

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

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

显然,内联“大”函数几乎没有什么好处(因为调用的开销是总运行时的一小部分),并且如果函数被多次调用(或者“可能被称为更多)比起一次“不是static”,编译器几乎肯定不会内联一个“大”函数。

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

答案 1 :(得分:1)

请检查我为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)

调用_ZN9TestClass14functionInlineEv

表示函数 functionInline 不是内联的。

现在看一下 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)  
}

因此, functionComplex 也不是内联的。

答案 2 :(得分:0)

不,不会内联。这是不可能的,因为编译器没有可用的非内联函数的主体定义可能位于另一个转换单元中。我认为正常函数是非内联函数。

答案 3 :(得分:0)

,如果您希望内联插入复杂功能,则必须同时指定inline关键字。
在实践中,使用__forceinline关键字(在Windows上,在Linux上为__always_inline)否则编译器会在有大量指令时忽略该关键字。

答案 4 :(得分:0)

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

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

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

在这种情况下,functionInline指定为内联,但functionComplex不指定。 functionComplex具有外部链接。编译器永远不会使用外部链接进行内联功能。

所以,对你的问题的一个简单回答是“不”正常(没有内联关键字和定义外部类的函数)函数永远不会被内联