[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
inline
From: |
Bruno Haible |
Subject: |
inline |
Date: |
Tue, 7 Nov 2006 14:38:25 +0100 |
User-agent: |
KMail/1.9.1 |
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