Fabricio
Fabricio

Reputation: 7935

Differences where declaring inline keyword

inline void foo();

int main() {
    foo(); return 0;
}

void foo(){
}

Is there any difference if setting foo's declaration as inline and not foo's definition? How about the opposite? How about marking them both as inline?

Upvotes: 3

Views: 212

Answers (1)

Shahbaz
Shahbaz

Reputation: 47603

This is all C11 says about inline (Note: inline is a function specifier, currently the only other function specifier is _Noreturn) (emphasis mine):

6.7.4

2. Function specifiers shall be used only in the declaration of an identifier for a function.

3. An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage.

5. A function specifier may appear more than once; the behavior is the same as if it appeared only once.

6. 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.138 The extent to which such suggestions are effective is implementation-defined.139

7. 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.

10. EXAMPLE 1 The declaration of an inline function with external linkage can result in either an external definition, or a definition available for use only within the translation unit. A file scope declaration with extern creates an external definition. The following example shows an entire translation unit.

inline double fahr(double t)
{
    return (9.0 * t) / 5.0 + 32.0;
}
inline double cels(double t)
{
    return (5.0 * (t - 32.0)) / 9.0;
}
extern double fahr(double); // creates an external definition
double convert(int is_fahr, double temp)
{
    /* A translator may perform inline substitutions */
    return is_fahr ? cels(temp) : fahr(temp);
}

11. Note that the definition of fahr is an external definition because fahr is also declared with extern, but the definition of cels is an inline definition. Because cels has external linkage and is referenced, an external definition has to appear in another translation unit (see 6.9); the inline definition and the external definition are distinct and either may be used for the call.

138 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.

139 For example, an implementation might never perform inline substitution, or might only perform inline substitutions to calls in the scope of an inline declaration

6.9

5. An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object.

J.1 Unspecified behavior

- Whether a call to an inline function uses the inline definition or the external definition of the function (6.7.4).

J.2 Undefined behavior

- A function with external linkage is declared with an inline function specifier, but is not also defined in the same translation unit (6.7.4).

J.3 Implementation-define behavior

J.3.8 Hints

- The extent to which suggestions made by using the inline function specifier are effective (6.7.4).


What this all means for human beings

  • 6.7.4.3: If you have an inline function that is also visible to the linker, it can't have static local variables. It also can't use file-scope variables/functions (defined like a global identifier but with static). (Note: can someone tell if my understanding is correct about this last sentence? It doesn't feel right.)

  • 6.7.4.6: Making a function inline doesn't force the compiler to act as if it's a macro. It just hints at the compiler that you want the function to be fast.

  • 6.7.4.7:

    1. If you have a static function, you are allowed to make it inline.
    2. If in a translation unit (TU) (say, preprocessed source file) the compiler sees an inline function declaration, somewhere in the same TU it should be able to find its definition.
    3. If everywhere you declare a function you put inline, then the compiler would see that function somewhat as static (but not exactly).
    4. If a function as in point 3 is used in the TU, the function would get an external linkage and therefore another implementation of it should exist in some other TU. It is the choice of the compiler to use the inlined version of the function or the external one.1
  • 138: No matter how many times you define the inline function in different TUs, they have the "same" address. I believe this also means that if you use a function pointer to store the address and then call the function through that pointer, the external definition of the function would be called.

  • 6.9.5: a normal function definition both declares and defines an external function. But as we saw before an inline definition of the function doesn't define a defintion that would be externally visible, even though it may declare an external function.

1 In your example, if you place inline in your definition of foo, you will get an error by gcc (during link phase) that foo has undefined reference. If you place another implementation of foo in the same file, you will get a redefinition error. This is consistent with what I said: all-inline declarations/definitions don't provide external linkage and if the function is used in the TU, it needs a definition in another TU.


Further reading:

Upvotes: 4

Related Questions