内联函数 - 它们与内联关键字完全相同的是什么?

时间:2017-01-05 17:32:04

标签: c++ function inline

this link中,什么是内联函数以及什么是内联关键字。我正在阅读它,因为我意识到我从未理解这两个概念的含义以及它们应该如何在实践中使用。我从我提供的链接中引用和评论

  

内联函数或内联变量(因为C ++ 17)是一个函数或   变量(自C ++ 17起)具有以下属性:

     

1)可能有   内联函数或变量的多个定义(因为   C ++ 17)在程序中只要每个定义出现在一个   不同的翻译单位。例如,内联函数或   内联变量(因为C ++ 17)可以在头文件中定义   包括在多个源文件中。

这里我已经有了解问题,声明是新标识符的规范,如

void func(void);

虽然定义是实际的实现,包括正文

void func(void) {
  //some code...
}

第1点意味着我可以提供不同的实现,只要它们位于不同的翻译单元中(即每个源文件的每个标头e一个实现),但我对此情况感到疑惑带有source.cc声明的源文件func和带有另一声明func翻译单元的头文件是source.cc+header.h对,并且在这种情况下声明了两次func没有任何意义,是吗?

  

2)内联函数或变量的定义(因为C ++ 17)必须   存在于访问它的翻译单元(不是   必须在访问点之前)。

这是通常的情况,我将定义与声明分开,第一个在头文件中,第二个在源文件中,如果我需要使用函数我只需要包含头文件吗?接入点将在链接阶段由源提供,是否正确?

  

3)具有外部链接的内联函数或变量(自C ++ 17开始)   (例如,未声明为static)具有以下附加属性:1)   必须在每个翻译单元中内联声明。 2)它有   每个翻译单位都有相同的地址。

你能提供一个简单的例子吗?我无法描述这种情况的实际案例。案例3)声明关键字inline是强制性的,除非要声明的函数是静态的。

到目前为止我所说的一切都是正确的吗?

实际上,当这样的函数非常小时,函数应该是内联的,但并不总是编译器会内联声明为内联的函数,例如,如果它有内部循环或递归(有效C ++状态如此)。一般来说,它依赖于编译器,我现在很奇怪......

假设我有两个功能,第一个是自包含的(它不会内部调用任何其他功能),第二个调用第一个功能(你可以假设它们是' re为了论证,这10条线都是。它们都应该内联声明吗?它们应该在头文件中声明吗?或者我应该在头文件中分离定义和源文件中的实现?什么会更好?

修改1

如果我通过示例工作,并通过相关的汇编代码分析,其中一个答案会更好。

我删除了之前的代码,因为它没有意义(-O3标记优化没有设置)。

我重新开始...我有5个文件header.hsrc.ccsrc1.ccsrc2.ccmain.cc。对于每个翻译单元,都会发布相关的汇编代码。

我已经以三种不同的方式处理这些文件,后来观察了生成的汇编代码,这有助于我理解内联关键字的工作原理。

示例1:

header.h

#ifndef HEADER_H_
#define HEADER_H_

int func(int a, int b);
int test_1();
int test_2();

#endif /* HEADER_H_ */

src.cc

#include "header.h"

int func(int a, int b)
{
   return a + b;
}

src1.cc

#include "header.h"

int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}

src2.cc

#include "header.h"

int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}

main.cc

int main(int argc, char** argv)
{
   test_1();
   test_2();
   test_1();
   test_2();
}

装配1:

src.s

GAS LISTING /tmp/cc0j97WY.s             page 1


   1                    .file   "src.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z4funcii
   6                    .type   _Z4funcii, @function
   7                _Z4funcii:
   8                .LFB2:
   9 0000 8D043E        leal    (%rsi,%rdi), %eax
  10 0003 C3            ret
  11                .LFE2:
  12                    .size   _Z4funcii, .-_Z4funcii
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB2
  40 002c 04000000      .long   .LFE2-.LFB2
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits

src1.s

GAS LISTING /tmp/cchSilt1.s             page 1


   1                    .file   "src1.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_1v
   6                    .type   _Z6test_1v, @function
   7                _Z6test_1v:
   8                .LFB2:
   9 0000 BE070000      movl    $7, %esi
   9      00
  10 0005 BF030000      movl    $3, %edi
  10      00
  11 000a E9000000      jmp _Z4funcii
  11      00
  12                .LFE2:
  13                    .size   _Z6test_1v, .-_Z6test_1v
  14                .globl __gxx_personality_v0
  15                    .section    .eh_frame,"a",@progbits
  16                .Lframe1:
  17 0000 1C000000      .long   .LECIE1-.LSCIE1
  18                .LSCIE1:
  19 0004 00000000      .long   0x0
  20 0008 01            .byte   0x1
  21 0009 7A505200      .string "zPR"
  22 000d 01            .uleb128 0x1
  23 000e 78            .sleb128 -8
  24 000f 10            .byte   0x10
  25 0010 06            .uleb128 0x6
  26 0011 03            .byte   0x3
  27 0012 00000000      .long   __gxx_personality_v0
  28 0016 03            .byte   0x3
  29 0017 0C            .byte   0xc
  30 0018 07            .uleb128 0x7
  31 0019 08            .uleb128 0x8
  32 001a 90            .byte   0x90
  33 001b 01            .uleb128 0x1
  34 001c 00000000      .align 8
  35                .LECIE1:
  36                .LSFDE1:
  37 0020 14000000      .long   .LEFDE1-.LASFDE1
  38                .LASFDE1:
  39 0024 24000000      .long   .LASFDE1-.Lframe1
  40 0028 00000000      .long   .LFB2
  41 002c 0F000000      .long   .LFE2-.LFB2
  42 0030 00            .uleb128 0x0
  43 0031 00000000      .align 8
  43      000000
  44                .LEFDE1:
  45                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  46                    .section    .note.GNU-stack,"",@progbits

src2.s

GAS LISTING /tmp/cc2JMtt3.s             page 1


   1                    .file   "src2.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_2v
   6                    .type   _Z6test_2v, @function
   7                _Z6test_2v:
   8                .LFB2:
   9 0000 BE080000      movl    $8, %esi
   9      00
  10 0005 BF070000      movl    $7, %edi
  10      00
  11 000a E9000000      jmp _Z4funcii
  11      00
  12                .LFE2:
  13                    .size   _Z6test_2v, .-_Z6test_2v
  14                .globl __gxx_personality_v0
  15                    .section    .eh_frame,"a",@progbits
  16                .Lframe1:
  17 0000 1C000000      .long   .LECIE1-.LSCIE1
  18                .LSCIE1:
  19 0004 00000000      .long   0x0
  20 0008 01            .byte   0x1
  21 0009 7A505200      .string "zPR"
  22 000d 01            .uleb128 0x1
  23 000e 78            .sleb128 -8
  24 000f 10            .byte   0x10
  25 0010 06            .uleb128 0x6
  26 0011 03            .byte   0x3
  27 0012 00000000      .long   __gxx_personality_v0
  28 0016 03            .byte   0x3
  29 0017 0C            .byte   0xc
  30 0018 07            .uleb128 0x7
  31 0019 08            .uleb128 0x8
  32 001a 90            .byte   0x90
  33 001b 01            .uleb128 0x1
  34 001c 00000000      .align 8
  35                .LECIE1:
  36                .LSFDE1:
  37 0020 14000000      .long   .LEFDE1-.LASFDE1
  38                .LASFDE1:
  39 0024 24000000      .long   .LASFDE1-.Lframe1
  40 0028 00000000      .long   .LFB2
  41 002c 0F000000      .long   .LFE2-.LFB2
  42 0030 00            .uleb128 0x0
  43 0031 00000000      .align 8
  43      000000
  44                .LEFDE1:
  45                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  46                    .section    .note.GNU-stack,"",@progbits

main.s

GAS LISTING /tmp/cc5CfYBW.s             page 1


   1                    .file   "main.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl main
   6                    .type   main, @function
   7                main:
   8                .LFB2:
   9 0000 4883EC08      subq    $8, %rsp
  10                .LCFI0:
  11 0004 E8000000      call    _Z6test_1v
  11      00
  12 0009 E8000000      call    _Z6test_2v
  12      00
  13 000e E8000000      call    _Z6test_1v
  13      00
  14                    .p2align 4,,5
  15 0013 E8000000      call    _Z6test_2v
  15      00
  16 0018 31C0          xorl    %eax, %eax
  17 001a 4883C408      addq    $8, %rsp
  18                    .p2align 4,,1
  19 001e C3            ret
  20                .LFE2:
  21                    .size   main, .-main
  22                .globl __gxx_personality_v0
  23                    .section    .eh_frame,"a",@progbits
  24                .Lframe1:
  25 0000 1C000000      .long   .LECIE1-.LSCIE1
  26                .LSCIE1:
  27 0004 00000000      .long   0x0
  28 0008 01            .byte   0x1
  29 0009 7A505200      .string "zPR"
  30 000d 01            .uleb128 0x1
  31 000e 78            .sleb128 -8
  32 000f 10            .byte   0x10
  33 0010 06            .uleb128 0x6
  34 0011 03            .byte   0x3
  35 0012 00000000      .long   __gxx_personality_v0
  36 0016 03            .byte   0x3
  37 0017 0C            .byte   0xc
  38 0018 07            .uleb128 0x7
  39 0019 08            .uleb128 0x8
  40 001a 90            .byte   0x90
  41 001b 01            .uleb128 0x1
  42 001c 00000000      .align 8
  43                .LECIE1:
  44                .LSFDE1:
  45 0020 14000000      .long   .LEFDE1-.LASFDE1
  46                .LASFDE1:
  47 0024 24000000      .long   .LASFDE1-.Lframe1
  48 0028 00000000      .long   .LFB2
  49 002c 1F000000      .long   .LFE2-.LFB2
  50 0030 00            .uleb128 0x0
  51 0031 44            .byte   0x4
  52                    .long   .LCFI0-.LFB2
  53 0032 0E            .byte   0xe
GAS LISTING /tmp/cc5CfYBW.s             page 2


  54 0033 10            .uleb128 0x10
  55 0034 00000000      .align 8
  56                .LEFDE1:
  57                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  58                    .section    .note.GNU-stack,"",@progbits

示例2:

header.h

#ifndef HEADER_H_
#define HEADER_H_

inline int func(int a, int b)
{
   return a + b;
}
int test_1();
int test_2();

#endif /* HEADER_H_ */

src.cc

#include "header.h"

/*
int func(int a, int b)
{
   return a + b;
}*/

src1.cc

#include "header.h"

int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}

src2.cc

#include "header.h"

int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}

main.cc

int main(int argc, char** argv)
{
   test_1();
   test_2();
   test_1();
   test_2();
}

大会2:

src.s

GAS LISTING /tmp/cczLx8os.s             page 1


   1                    .file   "src.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits

src1.s

GAS LISTING /tmp/ccMFMy9s.s             page 1


   1                    .file   "src1.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_1v
   6                    .type   _Z6test_1v, @function
   7                _Z6test_1v:
   8                .LFB3:
   9 0000 B80A0000      movl    $10, %eax
   9      00
  10 0005 C3            ret
  11                .LFE3:
  12                    .size   _Z6test_1v, .-_Z6test_1v
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB3
  40 002c 06000000      .long   .LFE3-.LFB3
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits

src2.s

GAS LISTING /tmp/ccNXXmLv.s             page 1


   1                    .file   "src2.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl _Z6test_2v
   6                    .type   _Z6test_2v, @function
   7                _Z6test_2v:
   8                .LFB3:
   9 0000 B80F0000      movl    $15, %eax
   9      00
  10 0005 C3            ret
  11                .LFE3:
  12                    .size   _Z6test_2v, .-_Z6test_2v
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB3
  40 002c 06000000      .long   .LFE3-.LFB3
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits

main.s

GAS LISTING /tmp/cc2cc5rp.s             page 1


   1                    .file   "main.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl main
   6                    .type   main, @function
   7                main:
   8                .LFB3:
   9 0000 4883EC08      subq    $8, %rsp
  10                .LCFI0:
  11 0004 E8000000      call    _Z6test_1v
  11      00
  12 0009 E8000000      call    _Z6test_2v
  12      00
  13 000e E8000000      call    _Z6test_1v
  13      00
  14                    .p2align 4,,5
  15 0013 E8000000      call    _Z6test_2v
  15      00
  16 0018 31C0          xorl    %eax, %eax
  17 001a 4883C408      addq    $8, %rsp
  18                    .p2align 4,,1
  19 001e C3            ret
  20                .LFE3:
  21                    .size   main, .-main
  22                .globl __gxx_personality_v0
  23                    .section    .eh_frame,"a",@progbits
  24                .Lframe1:
  25 0000 1C000000      .long   .LECIE1-.LSCIE1
  26                .LSCIE1:
  27 0004 00000000      .long   0x0
  28 0008 01            .byte   0x1
  29 0009 7A505200      .string "zPR"
  30 000d 01            .uleb128 0x1
  31 000e 78            .sleb128 -8
  32 000f 10            .byte   0x10
  33 0010 06            .uleb128 0x6
  34 0011 03            .byte   0x3
  35 0012 00000000      .long   __gxx_personality_v0
  36 0016 03            .byte   0x3
  37 0017 0C            .byte   0xc
  38 0018 07            .uleb128 0x7
  39 0019 08            .uleb128 0x8
  40 001a 90            .byte   0x90
  41 001b 01            .uleb128 0x1
  42 001c 00000000      .align 8
  43                .LECIE1:
  44                .LSFDE1:
  45 0020 14000000      .long   .LEFDE1-.LASFDE1
  46                .LASFDE1:
  47 0024 24000000      .long   .LASFDE1-.Lframe1
  48 0028 00000000      .long   .LFB3
  49 002c 1F000000      .long   .LFE3-.LFB3
  50 0030 00            .uleb128 0x0
  51 0031 44            .byte   0x4
  52                    .long   .LCFI0-.LFB3
  53 0032 0E            .byte   0xe
GAS LISTING /tmp/cc2cc5rp.s             page 2


  54 0033 10            .uleb128 0x10
  55 0034 00000000      .align 8
  56                .LEFDE1:
  57                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  58                    .section    .note.GNU-stack,"",@progbits

示例3:

header.h

#ifndef HEADER_H_
#define HEADER_H_

inline int func(int a, int b)
{
   return a + b;
}
inline int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}
inline int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}

#endif /* HEADER_H_ */

src.cc

#include "header.h"

/*
int func(int a, int b)
{
   return a + b;
}*/

src1.cc

#include "header.h"

/*int test_1()
{
   int a, b, c;
   a = 3;
   b = 7;
   c = func(a, b);
   return c;
}*/

src2.cc

#include "header.h"


/*int test_2()
{
   int a, b, c;
   a = 7;
   b = 8;
   c = func(a, b);
   return c;
}*/

main.cc

int main(int argc, char** argv)
{
   test_1();
   test_2();
   test_1();
   test_2();
}

大会3:

src.s

GAS LISTING /tmp/ccfPkzMC.s             page 1


   1                    .file   "src.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits

src1.s

GAS LISTING /tmp/cckRkoWG.s             page 1


   1                    .file   "src1.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits

src2.s

GAS LISTING /tmp/ccfmb3gI.s             page 1


   1                    .file   "src2.cc"
   2                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
   3                    .section    .note.GNU-stack,"",@progbits

main.s

GAS LISTING /tmp/ccGBsR8z.s             page 1


   1                    .file   "main.cc"
   2                    .text
   3                    .align 2
   4                    .p2align 4,,15
   5                .globl main
   6                    .type   main, @function
   7                main:
   8                .LFB5:
   9 0000 31C0          xorl    %eax, %eax
  10 0002 C3            ret
  11                .LFE5:
  12                    .size   main, .-main
  13                .globl __gxx_personality_v0
  14                    .section    .eh_frame,"a",@progbits
  15                .Lframe1:
  16 0000 1C000000      .long   .LECIE1-.LSCIE1
  17                .LSCIE1:
  18 0004 00000000      .long   0x0
  19 0008 01            .byte   0x1
  20 0009 7A505200      .string "zPR"
  21 000d 01            .uleb128 0x1
  22 000e 78            .sleb128 -8
  23 000f 10            .byte   0x10
  24 0010 06            .uleb128 0x6
  25 0011 03            .byte   0x3
  26 0012 00000000      .long   __gxx_personality_v0
  27 0016 03            .byte   0x3
  28 0017 0C            .byte   0xc
  29 0018 07            .uleb128 0x7
  30 0019 08            .uleb128 0x8
  31 001a 90            .byte   0x90
  32 001b 01            .uleb128 0x1
  33 001c 00000000      .align 8
  34                .LECIE1:
  35                .LSFDE1:
  36 0020 14000000      .long   .LEFDE1-.LASFDE1
  37                .LASFDE1:
  38 0024 24000000      .long   .LASFDE1-.Lframe1
  39 0028 00000000      .long   .LFB5
  40 002c 03000000      .long   .LFE5-.LFB5
  41 0030 00            .uleb128 0x0
  42 0031 00000000      .align 8
  42      000000
  43                .LEFDE1:
  44                    .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-54)"
  45                    .section    .note.GNU-stack,"",@progbits

示例1和示例3是我特别感兴趣的,因为它们应该以某种方式突出显示内联函数和非内联函数之间的区别(在链接的第1,2和3点之后)我在上面发布了),与内联版本相比,我没有看到非内联函数中缺少任何属性。有人可以突出显示我的差异(再次点1,2和3)?

3 个答案:

答案 0 :(得分:43)

也许一些例子会有所帮助。

1。传统的编译库

<强> foo.h中:

extern int x;
int * f();

<强> Foo.cpp中:

#include "foo.h"

int x = 25;

int * f() { return &x; }

用户包括foo.h,需要在包含foo.cpp的翻译单元中进行关联才能拨打f。每个这样的调用都返回相同的地址。

2。单独的TU局部变量

<强> foo.h中:

static int x = 35;
static int * f() { return &x; }

包含foo.h的每个TU都会获得一个单独的不同的函数f,调用这会产生每个TU的唯一值。

3。宝贝第一次违反ODR

<强> foo.h中:

static int x = 45;
inline int * f() { return &x; }

这似乎是一个仅限标头的库,但如果foo.h包含在多个TU中,则构成ODR违规,因为f将被定义多次,但不是全部它的定义是相同的。

这是一个常见的错误。解决方法包括制作x模板或将x替换为int & x() { static int impl = 45; return impl; }等功能。请注意,如果省略static,由于x的多个定义,您很可能会收到链接器错误; static似乎“使代码编译”。

4。 C ++ 17救援:正确的标题库

<强> foo.h中:

inline int x = 55;
inline int * f() { return &x; }

此版本在功能上等同于(1),但不需要专用的翻译单元来包含xf的定义。

答案 1 :(得分:15)

  

第1点意味着我可以提供不同的实现,只要它们位于不同的翻译单元

不,它说你可以拥有多个实现。它并没有说它们可以是不同的。实现必须完全相同。

  

我感到困惑的是,我有一个源文件source.cc,其中包含func的声明,另一个声明为func的头文件是翻译单元source.cc+header.h 1}}并且在这种情况下宣布两次func没有任何意义,是吗?

您可以根据需要多次声明一个函数,无论它是否为内联,都可以使用多个翻译单元。内联不是一个因素。

  
    

2)内联函数或变量的定义(因为C ++ 17)必须存在于访问它的翻译单元中。

  
     

这是通常的情况,我将定义与声明分开,第一个在头文件中,第二个在源文件中,如果我需要使用函数我只需要包含头文件吗?接入点将在链接阶段由源提供,是否正确?

不,在链接阶段之前,内联函数的定义必须存在于使用它的每个TU中。 多个TU中允许定义的内联函数的目的;当您想要将函数的定义放在标题中时,可以使用inline

  

案例3)声明关键字内联是强制性的,除非要声明的函数是静态的。

不,它根本没有说,我不知道你怎么能这样解释它。它只是说inline static函数具有内部链接,inlinestatic函数具有外部链接,子点3.1和3.2适用于{{1}具有外部链接的函数。

  

实际上,当这样的函数非常小时,函数应该是内联的,但并不总是编译器会内联声明为内联的函数,例如,如果它有内部循环或递归(有效C ++状态如此)。一般情况下,它依赖于编译器,我现在很奇怪......

     

假设我有两个函数,第一个是自包含的(它不在内部调用任何其他函数),第二个调用是第一个函数(你可以假设它们都是10行为了参数) 。它们都应该内联声明吗?它们应该在头文件中声明吗?或者我应该在头文件中分离定义和源文件中的实现?什么会更好?

优化器是否将执行函数体的内联替换与它是否是inline函数没有很强的相关性。 优化器会自行判断是否执行函数的内联替换,无论它是否为inline函数。如果要执行,则声明函数inline将他们的定义放在标题中。

答案 2 :(得分:8)

让我们暂时讨论inline是否被强制的问题(目前还有很多讨论)。

内联函数相当于在函数调用(调用)的位置粘贴函数的内容。

所以给出以下内容:

void Hello()
{
  std::cout << "Hello\n";
}

int main()
{
  Hello();
  return 0;
}

当内联Hello函数时,您将获得相当于:

int main()
{
  // Hello();
  std::cout << "Hello\n"; // This is the content of function Hello().
  return 0;
}

允许编译器内联未标记为内联的函数。此功能通常由优化设置触发。

编辑1:内联的常见原因
内联函数的一个常见原因是当内容小于或等于调用函数的开销时。

有一个与调用函数相关的协议,例如将参数移动到堆栈或寄存器。无论函数的大小如何,协议都存在。因此,内联将删除调用协议(从而减少程序代码大小并提高性能)。

内联的另一个原因是减少函数调用的数量。在某些处理器中,分支指令(函数调用)会导致重新加载指令高速缓存(或管道)。这需要时间。内联减少了函数调用并缩短了执行时间。

编辑2:代码膨胀
创建函数的一个原因是减少代码大小。内联大型函数可能会导致代码膨胀或程序大小增加。

代码膨胀和函数内联属于 Time vs. Space 权衡。内联大型函数可能会加快执行速度,但您正在为它进行交易。将公共代码放入函数可能会减小程序的大小,但需要更多的时间来执行。