Just for info. Here are some notes I collected about 'inline' three months
ago. If it's too much details, skip the text until "Results" at the bottom :-)

-------------------------------------------------------------------------------
Use of 'inline' in function definitions
=======================================


Standards:
  * ANSI/ISO C++

    3.2.(3)
    An inline function shall be defined in every  transla-
    tion unit in which it is used.

    7.1.2.(2)
    A  function declaration (_dcl.fct_, _class.mfct_, _class.friend_) with
    an inline specifier declares an inline function.  The inline specifier
    indicates  to the implementation that inline substitution of the func-
    tion body at the point of call is to be preferred to the  usual  func-
    tion  call  mechanism.   An  implementation is not required to perform
    this inline substitution at the point of call; however, even  if  this
    inline  substitution  is omitted, the other rules for inline functions
    defined by _dcl.fct.spec_ shall still be respected.

    7.1.2.(3) footnote
    The inline keyword has no effect on the linkage of a function.

    7.1.2.(4)
    An inline function shall be defined in every translation unit in which
    it  is  used  and shall have exactly the same definition in every case
    (_basic.def.odr_).  [Note: a  call  to  the  inline  function  may  be
    encountered  before its definition appears in the translation unit.  ]
    If a function with external linkage is declared inline in one transla-
    tion  unit,  it  shall  be declared inline in all translation units in
    which it appears; no diagnostic is required.  An inline function  with
    external linkage shall have the same address in all translation units.
    [Note: a static local variable in an  extern  inline  function  always
    refers to the same object.  ]

  * ISO C99

    6.2.2.(5)
    If the declaration of an identifier for a function has no storage-class
    specifier, its linkage is determined exactly as if it were declared with
    the storage-class specifier extern.
    [Note: This applies to function declarations only, not to function
    definitions!]

    6.7.4.(3)
    An inline definition of a function with external linkage shall not
    contain a definition of a modifiable object with static storage duration,
    and shall not contain a reference to an identifier with internal linkage.
    [I.e. what is explicitly allowed in C++ is forbidden in C.]

    6.7.4.(5)
    A function declared with an inline function specifier is an inline
    function. The function specifier may appear more than once; the behavior
    is the same as if it appeared only once. Making a function an inline
    function suggests that calls to the function be as fast as possible.
    The extent to which such suggestions are effective is implementation-
    defined.

    6.7.4.(6)
    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.

    6.7.4.(6) footnote
    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.

    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.
    If an identifier declared with external linkage is used in an expression
    (other than as part of the operand of a sizeof operator whose result is
    an integer constant), somewhere in the entire program there shall be
    exactly one external definition for the identifier; otherwise, there shall
    be no more than one.

    6.9.(5) footnote
    Thus, if an identifier declared with external linkage is not used in an
    expression, there need be no external definition for it.


Summary:
  * In C++, "static inline" is semantically equivalent to "static";
    "inline" and "extern inline" both designate the same definition in every
    compilation unit. The effects are very similar. The difference is that
    when using "inline" without "static", all instantiations of the function
    are identical (have the same address), and it is available through a simple
    "extern" declaration.
  * In C99, "static inline" is semantically equivalent to "static";
    "extern inline" is semantically equivalent to "extern" (in particular,
    multiple-definition errors can occur). "inline" without extern is a
    semantic nop, only a optimization hint for the compiler.


gcc-2.7.2.3 manual:

Note that in C and Objective C, unlike C++, the @code{inline} keyword
does not affect the linkage of the function.

If you specify both @code{inline} and @code{extern} in the function
definition, then the definition is used only for inlining.  In no case
is the function compiled on its own, not even if you refer to its
address explicitly.  Such an address becomes an external reference, as
if you had only declared the function, and had not defined it.

gcc-2.95.3 manual:

Likewise.

gcc-4.2-... manual:

Inline functions are included in the ISO C99 standard, but there are
currently substantial differences between what GCC implements and what
the ISO C99 standard requires.


Test case:
=========================== foo1.c ===========================
extern inline int plus (int a, int b) { return a+b; }

int main () { return plus (-2, 2); }
=========================== foo2.c ===========================
extern inline int plus (int a, int b) { return a+b; }

int foo (int x) { return plus(x, 42); }
=========================== foo3.c ===========================
extern inline int plus (int a, int b) { return a+b; }

int (*f3) (int, int) = plus;
=========================== foo4.c ===========================
extern int plus (int a, int b);

int (*f4) (int, int) = plus;
==============================================================

* extern inline
         inline
  static inline
  static
  without a body is an error in C++ (Sun C++ error for foo4).

* extern inline:
with Sun C++:
  foo1, foo2 inlined;
  foo3 plus defined as extern (uses segment with LINK_ONCE_DISCARD -> no 
multiple definition errors);
  foo4 plus undefined (can lead to undefined reference error).
with g++ 2.95.3 ... 4.2 unoptimizing:
  foo1, foo2, foo3 defined as extern (weak -> no multiple definition errors);
  foo4 plus undefined (cannot lead to undefined reference error).
with g++ 2.95.3 ... 4.2 optimizing:
  foo1, foo2 inlined;
  foo3 defined as extern (weak -> no multiple definition errors);
  foo4 plus undefined (can lead to undefined reference error).
with Sun C99:
  foo1, foo2, foo3 plus defined as extern (uses segment with LINK_ONCE_DISCARD 
-> no multiple definition errors);
  foo4 plus undefined (cannot lead to undefined reference error).
with gcc 2.95.3 ... 4.2 unoptimizing:
  foo1, foo2, foo3, foo4 plus undefined (can lead to undefined reference error).
with gcc 2.95.3 ... 4.2 optimizing:
  foo1, foo2 inlined;
  foo3, foo4 plus undefined (can lead to undefined reference error).

* inline:
with Sun C++:
  foo1, foo2 inlined;
  foo3 plus defined as extern (uses segment with LINK_ONCE_DISCARD -> no 
multiple definition errors);
  foo4 plus undefined (can lead to undefined reference error).
with g++ 2.95.3 ... 4.2 unoptimizing:
  foo1, foo2, foo3 defined as extern (weak -> no multiple definition errors);
  foo4 plus undefined (cannot lead to undefined reference error).
with g++ 2.95.3 ... 4.2 optimizing:
  foo1, foo2 inlined;
  foo3 defined as extern (weak -> no multiple definition errors);
  foo4 plus undefined (can lead to undefined reference error).
with Sun C99:
  foo1, foo2, foo3, foo4 plus undefined (can lead to undefined reference error).
with gcc 2.95.3 ... 4.2:
  foo1, foo2, foo3 plus defined as extern (can lead to multiple definition 
errors).
  foo4 plus undefined (cannot lead to undefined reference error).

* static inline:
with Sun C++:
  foo1, foo2 inlined;
  foo3 plus defined as static;
  foo4 plus undefined (will lead to undefined reference error).
with g++ 2.95.3 ... 4.2, with Sun C99, with gcc 2.95.3 ... 4.2:
  foo1, foo2, foo3 plus defined as static;
  foo4 plus undefined (will lead to undefined reference error).


Compiler Bugs:
- No bug in C++ mode.
- gcc violates 6.7.4.(6), Sun C gets it right.
  This is listed in http://gcc.gnu.org/c99status.html.


Results:

  * "static inline" is safe to use and has the same semantics in C and in C++:
    it never leads to a globally defined symbol and never leads to an undefined
    symbol.

  * Use of "extern" to refer to functions defined with "inline" or
    "extern inline" is unreliable.
    (In C++, because of ISO C++ 7.1.2.(4).
    In C for references to "inline" functions, because of ISO C 6.7.4.(6).
    In C for references to "extern inline" functions, because gcc is buggy.)

  * The semantics of "may create a globally defined symbol, but avoid
    multiple-definition errors, assuming all definitions are equivalent"
    can be gotten
      - in C++ through "inline" or "extern inline" (both equivalent, portable),
      - with Sun C through "extern inline",
      - with GCC through "inline".

  * The semantics of "assume a definition in a different compilation unit"
    can be gotten
      - portably through "extern",
      - with Sun C through "inline",
      - with GCC through "extern inline".

  * The way to provide a function definition that has external linkage and is
    inlinable:
      - In C++, you _must_ put it into the .h file. "inline" or "extern inline"
        are both usable. "extern" declarations in compilation units that don't
        use the .h file are forbidden.
      - In C99, an "inline" definition goes into the .h file; an "extern" or
        "extern inline" definition must be present in exactly one compilation
        unit (and it may include the .h file). "extern" declarations in
        compilation units that don't use the .h file are possible.


There are three ways to emit a definition with external linkage with gcc:
1)
     inline int plus (int a, int b) { return a+b; }
2)
     extern inline int plus (int a, int b) { return a+b; }
     inline int plus (int a, int b) { return a+b; }
3)
     extern inline int plus (int a, int b) { return a+b; }
     extern int plus (int a, int b) { return a+b; }
[Note that in cases 2, 3, the opposite order of definitions gives an error!]


Which compilers don't yet support inline?
Solaris 7 cc    lacks inline entirely
HP-UX 11 cc     has an unusable inline (return type must not be a typedef)
IRIX 6 cc       has __inline but does not understand  extern __inline.
AIX 4 xlc       has __inline, uses the C99 semantics
OSF/1 5.1 cc    has inline, uses the C99 semantics


Reply via email to