In this article we compared different behavior of `static`, `inline` and `static inline` free functions in compiled binary. All the following test was done under g++ 7.1.1 on Linux amd64, ELF64. ## Test sources ### header.hpp ```cpp #pragma once inline int only_inline() { return 42; } static int only_static() { return 42; } static inline int static_inline() { return 42; } ``` ### a.cpp ```cpp #include "header.hpp" int a() { return static_inline() + only_inline() + only_static(); } ``` ### b.cpp ```cpp #include "header.hpp" int a(); int b() { return static_inline() + only_inline() + only_static(); } int main() { return a() + b(); } ``` ## Compiled binaries ### a.o ```bash readelf -sW a.o | c++filt -t # -s: symbol table # -W: display in wide format ``` ```cpp Symbol table '.symtab' contains 14 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS a.cpp 2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 3: 0000000000000000 0 SECTION LOCAL DEFAULT 4 4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 6: 0000000000000000 11 FUNC LOCAL DEFAULT 2 only_static() # local 7: 000000000000000b 11 FUNC LOCAL DEFAULT 2 static_inline() # local 8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 9: 0000000000000000 0 SECTION LOCAL DEFAULT 9 10: 0000000000000000 0 SECTION LOCAL DEFAULT 7 11: 0000000000000000 0 SECTION LOCAL DEFAULT 1 12: 0000000000000000 11 FUNC WEAK DEFAULT 6 only_inline() # weak 13: 0000000000000016 37 FUNC GLOBAL DEFAULT 2 a() ``` ### b.o ``` Symbol table '.symtab' contains 17 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS b.cpp 2: 0000000000000000 0 SECTION LOCAL DEFAULT 2 3: 0000000000000000 0 SECTION LOCAL DEFAULT 4 4: 0000000000000000 0 SECTION LOCAL DEFAULT 5 5: 0000000000000000 0 SECTION LOCAL DEFAULT 6 6: 0000000000000000 11 FUNC LOCAL DEFAULT 2 only_static() # LOCAL 7: 000000000000000b 11 FUNC LOCAL DEFAULT 2 static_inline() # LOCAL 8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 9: 0000000000000000 0 SECTION LOCAL DEFAULT 9 10: 0000000000000000 0 SECTION LOCAL DEFAULT 7 11: 0000000000000000 0 SECTION LOCAL DEFAULT 1 12: 0000000000000000 11 FUNC WEAK DEFAULT 6 only_inline() # WEAK 13: 0000000000000016 37 FUNC GLOBAL DEFAULT 2 b() 14: 000000000000003b 30 FUNC GLOBAL DEFAULT 2 main 15: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_ 16: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND a() ``` ### a.out As in compiled executable, every copies of symbol marked `LOCAL` will be preserved, while only one instance of `WEAK` symbols will only be preserved. ``` Symbol table '.symtab' contains 71 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000238 0 SECTION LOCAL DEFAULT 1 2: 0000000000000254 0 SECTION LOCAL DEFAULT 2 3: 0000000000000274 0 SECTION LOCAL DEFAULT 3 4: 0000000000000298 0 SECTION LOCAL DEFAULT 4 5: c0 0 SECTION LOCAL DEFAULT 5 6: 0000000000000368 0 SECTION LOCAL DEFAULT 6 7: 0000000000000412 0 SECTION LOCAL DEFAULT 7 8: 0000000000000420 0 SECTION LOCAL DEFAULT 8 9: 0000000000000440 0 SECTION LOCAL DEFAULT 9 10: 0000000000000518 0 SECTION LOCAL DEFAULT 10 11: 0000000000000530 0 SECTION LOCAL DEFAULT 11 12: 0000000000000540 0 SECTION LOCAL DEFAULT 12 13: 0000000000000550 0 SECTION LOCAL DEFAULT 13 14: 0000000000000774 0 SECTION LOCAL DEFAULT 14 15: 0000000000000780 0 SECTION LOCAL DEFAULT 15 16: 0000000000000784 0 SECTION LOCAL DEFAULT 16 17: 00000000000007f8 0 SECTION LOCAL DEFAULT 17 18: 0000000000200de0 0 SECTION LOCAL DEFAULT 18 19: 0000000000200de8 0 SECTION LOCAL DEFAULT 19 20: 0000000000200df0 0 SECTION LOCAL DEFAULT 20 21: 0000000000200fd0 0 SECTION LOCAL DEFAULT 21 22: 0000000000201000 0 SECTION LOCAL DEFAULT 22 23: 0000000000201018 0 SECTION LOCAL DEFAULT 23 24: 0000000000201028 0 SECTION LOCAL DEFAULT 24 25: 0000000000000000 0 SECTION LOCAL DEFAULT 25 26: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c 27: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 28: 0000000000000580 0 FUNC LOCAL DEFAULT 13 deregister_tm_clones 29: 00000000000005c0 0 FUNC LOCAL DEFAULT 13 register_tm_clones 30: 0000000000000610 0 FUNC LOCAL DEFAULT 13 __do_global_dtors_aux 31: 0000000000201028 1 OBJECT LOCAL DEFAULT 24 completed.6991 32: 0000000000200de8 0 OBJECT LOCAL DEFAULT 19 __do_global_dtors_aux_fin 33: 0000000000000650 0 FUNC LOCAL DEFAULT 13 frame_dummy 34: 0000000000200de0 0 OBJECT LOCAL DEFAULT 18 __frame_dummy_init_array_ 35: 0000000000000000 0 FILE LOCAL DEFAULT ABS a.cpp 36: 000000000000065a 11 FUNC LOCAL DEFAULT 13 only_static() # COPY 1 37: 0000000000000665 11 FUNC LOCAL DEFAULT 13 static_inline() # COPY 1 38: 0000000000000000 0 FILE LOCAL DEFAULT ABS b.cpp 39: 00000000000006a0 11 FUNC LOCAL DEFAULT 13 only_static() # COPY 2 40: 00000000000006ab 11 FUNC LOCAL DEFAULT 13 static_inline() # COPY 2 41: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c 42: 00000000000009e0 0 OBJECT LOCAL DEFAULT 17 __FRAME_END__ 43: 0000000000000000 0 FILE LOCAL DEFAULT ABS 44: 0000000000000784 0 NOTYPE LOCAL DEFAULT 16 __GNU_EH_FRAME_HDR 45: 0000000000201000 0 OBJECT LOCAL DEFAULT 22 _GLOBAL_OFFSET_TABLE_ 46: 0000000000200de8 0 NOTYPE LOCAL DEFAULT 18 __init_array_end 47: 0000000000200de0 0 NOTYPE LOCAL DEFAULT 18 __init_array_start 48: 0000000000200df0 0 OBJECT LOCAL DEFAULT 20 _DYNAMIC 49: 0000000000201018 0 NOTYPE WEAK DEFAULT 23 data_start 50: 0000000000000770 2 FUNC GLOBAL DEFAULT 13 __libc_csu_fini 51: 0000000000000550 43 FUNC GLOBAL DEFAULT 13 _start 52: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__ 53: 0000000000000670 37 FUNC GLOBAL DEFAULT 13 a() 54: 0000000000000774 0 FUNC GLOBAL DEFAULT 14 _fini 55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_ 56: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab 57: 0000000000000780 4 OBJECT GLOBAL DEFAULT 15 _IO_stdin_used 58: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable 59: 0000000000201018 0 NOTYPE GLOBAL DEFAULT 23 __data_start 60: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2 61: 0000000000201028 0 OBJECT GLOBAL HIDDEN 23 __TMC_END__ 62: 0000000000201020 0 OBJECT GLOBAL HIDDEN 23 __dso_handle 63: 0000000000000700 101 FUNC GLOBAL DEFAULT 13 __libc_csu_init 64: 0000000000201028 0 NOTYPE GLOBAL DEFAULT 24 __bss_start 65: 0000000000000695 11 FUNC WEAK DEFAULT 13 only_inline() # only one 66: 0000000000201030 0 NOTYPE GLOBAL DEFAULT 24 _end 67: 00000000000006b6 37 FUNC GLOBAL DEFAULT 13 b() 68: 0000000000201028 0 NOTYPE GLOBAL DEFAULT 23 _edata 69: 00000000000006db 30 FUNC GLOBAL DEFAULT 13 main 70: 0000000000000518 0 FUNC GLOBAL DEFAULT 10 _init ``` ## Conclusion - `inline` marks the symbol `WEAK`, which hints linker to choose arbitary *one* of definition in object files - `static` marks the symbol `LOCAL`, which restricts the symbol in current translation unit, and the linker may keep *multiple* instances of (possibly different) definition. - `static inline` generally works as `static`, but the `inline` keyword suggest compiler trying to inline this function. ## Extra credits In C++11 it is recommended to use function in anonymous namespace over `static` functions. What if we add the following code into `header.hpp`: ```cpp namespace { int anon_namespace() { return 42; } } ``` ### a.o ``` 8: 0000000000000016 11 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_114anon_namespaceEv # (anonymous namespace)::anon_namespace() ``` ### b.o ``` 8: 0000000000000016 11 FUNC LOCAL DEFAULT 2 _ZN12_GLOBAL__N_114anon_namespaceEv # (anonymous namespace)::anon_namespace() ``` ### a.out ``` 38: 0000000000000670 11 FUNC LOCAL DEFAULT 13 (anonymous namespace)::anon_namespace() 42: 00000000000006c8 11 FUNC LOCAL DEFAULT 13 (anonymous namespace)::anon_namespace() ``` You may notice that this is exactly the same as `static`, except for its mangled name. So why the commitee introduced anonymous namespace? Read https://stackoverflow.com/questions/4977252/why-an-unnamed-namespace-is-a-superior-alternative-to-static for explanation. ## Read more - https://stackoverflow.com/questions/10876930/should-one-never-use-static-inline-function - https://stackoverflow.com/questions/12836171/difference-between-an-inline-function-and-static-inline-function - https://stackoverflow.com/questions/22102919/static-vs-inline-for-functions-implemented-in-header-files