It can generate smaller code. The reason is that inline (as opposed to static inline ) will give an external communication function, so that all function calls from different translation units refer to the same logical function. With static inline each translation unit will receive a unique instance of the function instead, which can increase the size of the code if the compiler does not want to embed. (This is also cleaner encoding so as not to have multiple identical functions.)
The reason you need to extern somewhere is because it forces the compiler to generate an external function definition that can be called from other translation units. Without extern such an instance is not generated. The case without extern differs from the internal binding in that the inline definition provides only an “alternative” to the external definition of the function. An external definition must still exist (i.e., some translation function must use extern to generate an external definition), and the compiler can use it, rather than want to.
Here are some relevant standard (for C11: ISO / IEC 9899: 2011 §6.7.4 Function specifiers, ¶7):
Any function with internal communication can be a built-in function. For an external link function, the following restrictions apply: if the function is declared using the inline function specifier, then it must also be defined in the same translation unit. If all scope declarations for a function in a translation block include an inline function specifier without extern , then the definition in that translation unit is a built-in definition. The built-in definition does not provide an external definition of a function and does not prohibit an external definition in another translation unit. The built-in definition provides an alternative to an external definition that the translator can use to implement any function call in the same translation unit. It is not indicated whether the function call is using a built-in definition or an external definition. 140)
140) Since the built-in definition is different from the corresponding external definition and from any other corresponding built-in definitions in other translation units, all the corresponding objects with static storage duration is also different in each of the definitions.
By the way, inline IMO is often not worth it (as a hint - the compiler is still free not to embed) compared to just letting the compiler choose when to embed purely on its own. For modern compilers that support connection time optimization, the compiler can even embed functions in translation units if you pass the correct flags (e.g. -flto to GCC).
source share