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 inline
so 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 the inline
keyword 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
inline
specifier, or by explicitly adding the extern
specifier to the existing inline definition (declaring it as extern inline
).
- Or: remove the
inline
specifier 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
inline
function 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
inline
function 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 the inline
function specifier without extern
, 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.