use*_*759 36 c++ inline function
在此链接中,什么是内联函数以及什么是内联关键字.我正在阅读它,因为我意识到我从未理解这两个概念的含义以及它们应该如何在实践中使用.我在引用和评论我提供的链接
内联函数或内联变量(自C++ 17开始)是具有以下属性的函数或变量(自C++ 17起):
1)只要每个定义出现在不同的翻译单元中,程序中的内联函数或变量(自C++ 17)可能有多个定义.例如,内联函数或内联变量(自C++ 17)可以在包含在多个源文件中的头文件中定义.
在这里我已经有了解问题,声明是新标识符的规范
void func(void);
Run Code Online (Sandbox Code Playgroud)
而定义是实际的实现,包括正文
void func(void) {
//some code...
}
Run Code Online (Sandbox Code Playgroud)
第1点意味着我可以提供不同的实现,只要它们处于不同的翻译单元(即每个源文件的每个头文件一个实现),但我很困惑,因为我有一个source.cc带有声明的源文件func并且一个带有func翻译单元的另一个声明的头文件就是这对,source.cc+header.h并且在这种情况下声明了两次func没有任何意义,是吗?
2)内联函数或变量的定义(因为C++ 17)必须存在于访问它的转换单元中(不一定在访问点之前).
这是通常的情况,我将定义与声明分开,第一个在头文件中,第二个在源文件中,如果我需要使用函数我必须只包含头?接入点将在链接阶段由源提供,是否正确?
3)具有外部链接(例如,未声明为静态)的内联函数或变量(因为C++ 17)具有以下附加属性:1)必须在每个翻译单元中内联声明.2)每个翻译单元都有相同的地址.
你能提供一个简单的例子吗?我无法想象这种情况的实际案例.情况3)声明关键字inline是强制性的,除非要声明的函数是静态的.
我到目前为止所说的一切是否正确?
实际上,当这样的函数非常小时,函数应该是内联的,但并不总是编译器会内联声明为内联的函数,例如,如果它有内部循环或递归(有效C++状态如此).一般来说它依赖于编译器,我现在很奇怪......
假设我有两个函数,第一个是自包含的(它不会在内部调用任何其他函数),第二个调用是第一个(为了参数,你可以假设它们都是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_ */
Run Code Online (Sandbox Code Playgroud)
src.cc
#include "header.h"
int func(int a, int b)
{
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
src1.cc
#include "header.h"
int test_1()
{
int a, b, c;
a = 3;
b = 7;
c = func(a, b);
return c;
}
Run Code Online (Sandbox Code Playgroud)
src2.cc
#include "header.h"
int test_2()
{
int a, b, c;
a = 7;
b = 8;
c = func(a, b);
return c;
}
Run Code Online (Sandbox Code Playgroud)
main.cc
int main(int argc, char** argv)
{
test_1();
test_2();
test_1();
test_2();
}
Run Code Online (Sandbox Code Playgroud)
大会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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
电源
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
Run Code Online (Sandbox Code Playgroud)
例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_ */
Run Code Online (Sandbox Code Playgroud)
src.cc
#include "header.h"
/*
int func(int a, int b)
{
return a + b;
}*/
Run Code Online (Sandbox Code Playgroud)
src1.cc
#include "header.h"
int test_1()
{
int a, b, c;
a = 3;
b = 7;
c = func(a, b);
return c;
}
Run Code Online (Sandbox Code Playgroud)
src2.cc
#include "header.h"
int test_2()
{
int a, b, c;
a = 7;
b = 8;
c = func(a, b);
return c;
}
Run Code Online (Sandbox Code Playgroud)
main.cc
int main(int argc, char** argv)
{
test_1();
test_2();
test_1();
test_2();
}
Run Code Online (Sandbox Code Playgroud)
大会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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
电源
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
Run Code Online (Sandbox Code Playgroud)
例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_ */
Run Code Online (Sandbox Code Playgroud)
src.cc
#include "header.h"
/*
int func(int a, int b)
{
return a + b;
}*/
Run Code Online (Sandbox Code Playgroud)
src1.cc
#include "header.h"
/*int test_1()
{
int a, b, c;
a = 3;
b = 7;
c = func(a, b);
return c;
}*/
Run Code Online (Sandbox Code Playgroud)
src2.cc
#include "header.h"
/*int test_2()
{
int a, b, c;
a = 7;
b = 8;
c = func(a, b);
return c;
}*/
Run Code Online (Sandbox Code Playgroud)
main.cc
int main(int argc, char** argv)
{
test_1();
test_2();
test_1();
test_2();
}
Run Code Online (Sandbox Code Playgroud)
大会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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
电源
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
Run Code Online (Sandbox Code Playgroud)
Example 1 and example 3 are the ones I'm particularly interested in, because they should highlight somehow what is the difference between an inline function and a not inline function (following the points 1,2 and 3 of the link I posted above), I don't see any lack of properties in the not inline functions compared to the inline version. Can someone highlight the difference for me (again in terms of the points 1,2 and 3)?
Ker*_* SB 42
也许一些例子会有所帮助.
foo.h中:
extern int x;
int * f();
Run Code Online (Sandbox Code Playgroud)
Foo.cpp中:
#include "foo.h"
int x = 25;
int * f() { return &x; }
Run Code Online (Sandbox Code Playgroud)
用户包括foo.h并需要链接在包含的翻译单元foo.cpp中以便呼叫f.每个这样的调用都返回相同的地址.
foo.h中:
static int x = 35;
static int * f() { return &x; }
Run Code Online (Sandbox Code Playgroud)
每个包含的TU foo.h都会获得一个独立且不同的函数f,调用它会产生每个TU的唯一值.
foo.h中:
static int x = 45;
inline int * f() { return &x; }
Run Code Online (Sandbox Code Playgroud)
这似乎是一个仅限标题的库,但如果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; }
Run Code Online (Sandbox Code Playgroud)
该版本在功能上等同于(1),但并不需要一个专门的翻译单元包含的定义x和f.
Okt*_*ist 14
第1点意味着只要它们处于不同的翻译单元中,我就可以提供不同的实现
不,它说你可以拥有多个实现.它并没有说它们可以是不同的.实现必须完全相同.
我很困惑,因为我有一个
source.cc带声明的源文件func和一个带有另一个func翻译单元声明的头文件是这对source.cc+header.h,在这种情况下声明了两次func没有任何意义,是吗?
您可以根据需要多次声明一个函数,无论它是否是内联的,都可以使用多个翻译单元.内联不是一个因素.
2)内联函数或变量的定义(因为C++ 17)必须存在于访问它的转换单元中.
这是通常的情况,我将定义与声明分开,第一个在头文件中,第二个在源文件中,如果我需要使用函数我必须只包含头?接入点将在链接阶段由源提供,是否正确?
不,在链接阶段之前,每个使用它的TU都必须存在内联函数的定义.内联函数的目的是允许多个TU中的定义; 你使用inline,当你想要把一个函数的定义在一个头.
情况3)声明关键字内联是强制性的,除非要声明的函数是静态的.
不,它根本没有说,我不知道你怎么能这样解释它.它只是说一个inline static函数有内部链接,一个inline非static函数有外部链接,子点3.1和3.2适用于inline具有外部链接的函数.
实际上,当这样的函数非常小时,函数应该是内联的,但并不总是编译器会内联声明为内联的函数,例如,如果它有内部循环或递归(有效C++状态如此).一般来说它依赖于编译器,我现在很奇怪......
假设我有两个函数,第一个是自包含的(它不会在内部调用任何其他函数),第二个调用是第一个(为了参数,你可以假设它们都是10行).它们都应该内联声明吗?它们应该在头文件中声明吗?或者我应该在头文件中分离定义和源文件中的实现?什么会更好?
优化器是否将执行函数体的内联替换与它是否是inline函数没有很强的相关性.优化器将自己弄清楚是否执行函数的内联替换,无论它是否是inline函数.inline如果要将其定义放在标题中,则声明函数.
让我们暂时讨论是否inline被迫的问题(关于该主题的讨论很多).
内联函数等效于在函数调用(调用)的位置粘贴函数的内容.
所以给出以下内容:
void Hello()
{
std::cout << "Hello\n";
}
int main()
{
Hello();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当Hello函数内联时,您将获得相当于:
int main()
{
// Hello();
std::cout << "Hello\n"; // This is the content of function Hello().
return 0;
}
Run Code Online (Sandbox Code Playgroud)
允许编译器内联未标记为内联的函数.此功能通常由优化设置触发.
编辑1:内联
的常见原因内联函数的一个常见原因是内容小于或等于调用函数的开销.
有一个与调用函数相关的协议,例如将参数移动到堆栈或寄存器.无论函数的大小如何,协议都存在.因此,内联将删除调用协议(从而减少程序代码大小并提高性能).
内联的另一个原因是减少函数调用的数量.在某些处理器中,分支指令(函数调用)会导致重新加载指令高速缓存(或管道).这需要时间.内联减少了函数调用并缩短了执行时间.
编辑2:代码膨胀
创建函数的一个原因是减少代码大小.内联大型函数可能会导致代码膨胀或程序大小增加.
代码膨胀和函数内联属于Time vs. Space权衡.内联大型函数可能会加快执行速度,但您正在为它进行交易.将公共代码放入函数可能会减小程序的大小,但需要更多的时间来执行.
| 归档时间: |
|
| 查看次数: |
2149 次 |
| 最近记录: |