在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.h
,src.cc
,src1.cc
,src2.cc
和main.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)?
答案 0 :(得分:43)
也许一些例子会有所帮助。
<强> foo.h中:强>
extern int x;
int * f();
<强> Foo.cpp中:强>
#include "foo.h"
int x = 25;
int * f() { return &x; }
用户包括foo.h
,需要在包含foo.cpp
的翻译单元中进行关联才能拨打f
。每个这样的调用都返回相同的地址。
<强> foo.h中:强>
static int x = 35;
static int * f() { return &x; }
包含foo.h
的每个TU都会获得一个单独的和不同的函数f
,调用这会产生每个TU的唯一值。
<强> 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
似乎“使代码编译”。
<强> foo.h中:强>
inline int x = 55;
inline int * f() { return &x; }
此版本在功能上等同于(1),但不需要专用的翻译单元来包含x
和f
的定义。
答案 1 :(得分:15)
第1点意味着我可以提供不同的实现,只要它们位于不同的翻译单元
不,它说你可以拥有多个实现。它并没有说它们可以是不同的。实现必须完全相同。
我感到困惑的是,我有一个源文件
source.cc
,其中包含func
的声明,另一个声明为func
的头文件是翻译单元source.cc+header.h
1}}并且在这种情况下宣布两次func
没有任何意义,是吗?
您可以根据需要多次声明一个函数,无论它是否为内联,都可以使用多个翻译单元。内联不是一个因素。
2)内联函数或变量的定义(因为C ++ 17)必须存在于访问它的翻译单元中。
这是通常的情况,我将定义与声明分开,第一个在头文件中,第二个在源文件中,如果我需要使用函数我只需要包含头文件吗?接入点将在链接阶段由源提供,是否正确?
不,在链接阶段之前,内联函数的定义必须存在于使用它的每个TU中。 多个TU中允许定义的内联函数的目的;当您想要将函数的定义放在标题中时,可以使用inline
。
案例3)声明关键字内联是强制性的,除非要声明的函数是静态的。
不,它根本没有说,我不知道你怎么能这样解释它。它只是说inline
static
函数具有内部链接,inline
非static
函数具有外部链接,子点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 权衡。内联大型函数可能会加快执行速度,但您正在为它进行交易。将公共代码放入函数可能会减小程序的大小,但需要更多的时间来执行。