OP's function is declared as inline double square(double); (actually declared as part of the function definition in OP's code) and has a definition in the same translation unit. Because the function does not have internal linkage (i.e. it was not declared static, and was not explicitly declared extern, the inline function definition does not constitute an external definition of the function. For a call to a function not declared with internal linkage (i.e. not declared static), the compiler is free to use an inline definition of the function or to call the external function. In OP's case, the compiler chose to call the external function, but no definition of the function with external linkage has been provided, so the program failed to link.
There are three possible solutions:
- Either: declare the function as static inlineso that the function definition is an inline function with internal linkage. The compiler is free to translate calls to the function as an actual function call or as an inline function call, with theinlinekeyword acting as a hint to the compiler that inline calls are preferred by the programmer.
- Or: provide an external definition of the function. That can be done either by duplicating the function definition without the inlinespecifier, or by explicitly adding theexternspecifier to the existing inline definition (declaring it asextern inline).
- Or: remove the inlinespecifier to turn the function definition into an external function definition.
For reference, see C17/C18 section 6.7.4 paragraphs 6 and 7 and footnotes 140, 141 and 142:
- A function declared with an inlinefunction specifier is an inline function. Making a function an inline function suggests that calls to the function be as fast as possible.140) The extent to which such
suggestions are effective is implementation-defined.141)
- Any function with internal linkage can be an inline function. For a function with external linkage, the following restrictions apply: If a function is declared with an inlinefunction specifier, then it shall also be defined in the same translation unit. If all of the file scope declarations for a function in a translation unit include theinlinefunction specifier withoutextern, then the definition in that translation unit is an inline definition. An inline definition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition.142)
140) By using, for example, an alternative to the usual function call mechanism, such as “inline substitution”. Inline substitution is not textual substitution, nor does it create a new function. Therefore, for example, the expansion of a macro used within the body of the function uses the definition it had at the point the function body appears, and not where the
function is called; and identifiers refer to the declarations in scope where the body occurs. Likewise, the function has a single address, regardless of the number of inline definitions that occur in addition to the external definition.
141) For example, an implementation might never perform inline substitution, or might only perform inline substitutions to
calls in the scope of an inline declaration.
142) Since an inline definition is distinct from the corresponding external definition and from any other corresponding inline definitions in other translation units, all corresponding objects with static storage duration are also distinct in each of the definitions.