There is a constraint 6.7.4(p3):
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.
Consider the following example:
static const int i = 10;
void do_print(void);
inline void do_print(void){
printf("%d/n", i); //Reference to an identifier with internal linkage
//constraint violation
}
DEMO
Here the inline definition of a function with external linkage uses an identifier with internal linkage. So according to 5.1.1.3(p1):
A conforming implementation shall produce at least one diagnostic
message (identified in an implementation-defined manner) if a
preprocessing translation unit or translation unit contains a
violation of any syntax rule or constraint, even if the behavior is
also explicitly specified as undefined or implementation-defined.
I expected the violation of this constraint is reported by the compiler somehow (some warning). But the code compiles just fine with no warnings or some other message produced.
The question is: Why is no diagnostic message produced in case of the constraint violation above?
The question is: Why is no diagnostic message produced in case of the constraint violation above?
Because your compiler is non-conforming in this regard.
That's really all there is to it. You have analyzed the text of the standard correctly, and applied it correctly to the code presented. A conforming implementation must emit a diagnostic about the reference to variable i by the inline implementation of do_print. An implementation that does not is, ergo, non-conforming.
I note at this point that some compilers are non-conforming in this general way -- omitting required diagnostics -- by default, while providing an option for turning on these mandatory diagnostics. This is the function of the -pedantic option in GCC, for example. However, I find that my (somewhat dated) version of GCC does not warn about your code even when -pedantic is specified.
cppreference has a paragraph that explains the rationale behind that:
If a function is declared inline in some translation units, it does not need to be declared inline everywhere: at most one translation unit may also provide a regular, non-inline non-static function, or a function declared extern inline. This one translation unit is said to provide the external definition. One external definition must exist in the program if the name of the function with external linkage is used in an expression, see one definition rule.
If the external definition exists in the program, the address of the function is always the address of the external function, but when this address is used to make a function call, it's unspecified whether the inline definition (if present in the translation unit) or the external definition is called.
A note also says (emphasize mine):
The inline keyword was adopted from C++, but in C++, if a function is declared inline, it must be declared inline in every translation unit, and also every definition of an inline function must be exactly the same (in C, the definitions may be different, as long as the behavior of the program does not depend on the differences). On the other hand, C++ allows non-const function-local statics and all function-local statics from different definitions of an inline function are the same in C++ but distinct in C.
That means that if a local inline function uses a static const value in one translation unit, a non inline function with same name could be defined in a different translation unit with a different value for the static const variable, leading to explicit UB because it is unspecified whether the compiler will use the local inline of the global non inline version.
Related
0.c
int i = 5;
int main(){
return i;
}
1.c
int i;
Above compiles fine with gcc 0.c 1.c without any link errors about multiple definitions. The reason is i gets generated as common blocks (-fcommon which is the default behaviour in gcc).
The proper way to do this is using the extern keyword which is missing here.
I have been searching online to see if this is undefined behaviour or not, some post say it is, some say it isn't and it's very confusing:
It is UB
Is having multiple tentative definitions in separate files undefined behaviour?
Why can I define a variable twice in C?
How do I use extern to share variables between source files?
http://port70.net/~nsz/c/c11/n1570.html#J.2
An identifier with external linkage is used, but in the program there does not exist exactly one external definition for the identifier, or the identifier is not used and there exist multiple external definitions for the identifier (6.9).
It is NOT UB
Global variables and the .data section
Defining an extern variable in multiple files in C
Does C have One Definition Rule like C++?
Look for -fno-common:
https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Code-Gen-Options.html
So which one is it? is using -fcommon one of the few places where having multiple definition is allowed and the compiler sorts it out for you? or it is still UB?
Analysis of the code according to the C Standard
This is covered in section 6.9/5 of the latest C Standard:
Semantics
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 or _Alignof 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.
The term "external definition" should not be confused with "external linkage" or the extern keyword, those are are entirely different concepts that happen to have similar spelling.
"external definition" means a definition that is not tentative, and not inside a function.
Regarding tentative definition, ths is covered by 6.9.2/2:
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static , constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.
So in your file 1.c, as per 6.9.2/2 the behaviour is exactly as if it had said int i = 0; instead. Which would be an external definition. This means 0.c and 1.c both behave as if they had external definitions which violates the rule 6.9/5 saying there shall be no more than one external definition.
Violating a semantic rule means the behaviour is undefined with no diagnostic required.
Explanation of what "undefined behaviour" means
See also: Undefined, unspecified and implementation-defined behavior
In case it is unclear, the C Standard saying "the behaviour is undefined" means that the C Standard does not define the behaviour. The same code built on different conforming implementations (or rebuilt on the same conforming implementation) may behave differently, including rejecting the program , accepting it, or any other outcome you might imagine.
(Note - some programs can have the defined-ness of their behaviour depend on runtime conditions; those programs cannot be rejected at compile-time and must behave as specified unless the condition occurs that causes the behaviour to be undefined. But that does not apply to the program in this question since all possible executions would encounter the violation of 6.9/5).
Compiler vendors may or may not provide stable and/or documented behaviour for cases where the C Standard does not define the behaviour.
For the code in your question it is common (ha ha) for compiler vendors to provide reliable behaviour ; this is documented in a non-normative Annex J.5.11 to the Standard:
J.5 Common extensions
J.5.11 Multiple external definitions
1 There may be more than one external definition for the identifier of an object, with or without the explicit use of the keyword extern ; if the definitions disagree, or more than one is initialized, the behavior is undefined (6.9.2).
It seems the gcc compiler implements this extension if -fcommon switch is provided, and disables it if -fno-common is provided (and the default setting may vary between compiler versions).
Footnote: I intentionally avoid using the word "defined" in relation to behaviour that is not defined by the C Standard as it seems to me that is one of the cause of confusion for OP.
From the C18 standard:
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.
Then we read:
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.
I've written a bit of code to check if the function is actually inline or not. I've used this restriction to find out:
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.
This is the code:
static int n = 5;
void inline foo() { n = 66; }
void inline foo(); // remove 'inline' in second version
int main() {
return 0;
}
When compiling this I get a warning saying that the inline function is using a static object, which means that foo() is, effectively, an inline function, and so it provides an inline (not external) definition. However, when I remove the inline specifier from the indicated line, I don't get the warning anymore. According to the standard, it's not an inline definition, so I guess it's providing an external definition.
What the standard is not saying, or at least I cannot see it, is whether an inline function that provides an external definition stops being an inline function, or not. According to my test, it does stop being an inline function.
If I'm right in my conclusions, which I don't know, another question arises: why an extern inline function is a useless thing?
In the question you try things in the compiler to try and deduce the language rules. This is generally a bad idea, because (a) in many situations the effect of breaking the rules is hard to observe, and (b) the compiler might be bugged. Instead, the Standard is an authoritative source for what the language rules are, so the question should be answered by referring to the Standard.
Moving on: your code contains a constraint violation of C11 6.7.4/3, which you quoted in your question. The effect of a constraint violation is that the compiler must issue a diagnostic, which it did.
Then you ask about some modification, I assume you mean the following code:
static int n = 5;
void inline foo() { n = 66; }
void foo();
int main() { return 0; }
As covered by the first sentence you quoted (from 6.7.4/7), the definition of foo() is not an inline definition, because it is not true that all of the file-scope declarations in the TU include the inline specifier without extern. (That sentence is intended to deny the antecedent).
Since it is not an inline definition, there is no problem with n = 66 and the code is correct.
What the standard is not saying, or at least I cannot see it, is whether an inline function that provides an external definition stops being an inline function, or not
An inline function definition is never an external definition. This is clearly stated in 6.7.4/7 "An inline definition does not provide an external definition for the function".
Maybe your confusion arises from conflating the concepts "inline function definition" and "function definition with the inline specifier".
another question arises: why an extern inline function is a useless thing?
If you mean the keywords extern inline that is another topic that was not touched on by this question, see here. Inline functions with external linkage are certainly not useless .
I feel I need to answer myself, as this is even more complex than I expected at the beginning, and new facts have arisen during my research since I wrote the question. This is more like my own conclusions, but I feel I'm in the right path. So I need to share. Feedback and confirmation/rejection will be most appreciated.
In the first place, take a look at this code:
void inline foo() { return; }
int main() {
foo();
return 0;
}
It might seem like a simple code, but the fact is that it doesn't compile. Well, actually, it compiles, but it fails in the linker step. Why? Let's read the full difficult-to-understand paragraph from the standard:
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.
From "It is unspecified whether a call to the function uses the inline definition or the external definition" we get the answer of why it didn't compile (link) well. My implementation (GCC) chose the external version. And the linker doesn't know about such external function.
The standard says an inline definition "does not forbid an external definition in another translation unit". Actually it doesn't, but it even makes mandatory to define it elsewhere if the function is called from the present translation unit and the implementation chooses to call the external version.
Then, another question arises: if the implementation choses to call the external definition, or the inline definition, why is it necessary to define both? Well I found the answer in GCC documentation: you never know when one will be chosen or the other. For instance, GCC chooses the external version when no optimizer switches are indicated. For many optimized code configurations, inline versions will be chosen.
And regarding the question about why inline extern functions could be useless, actually they are not. External functions can also be inlined. Check this document: https://gcc.gnu.org/onlinedocs/gcc/Inline.html
An external inline function can be used and inlined from other translation units, it just doesn't create an inline definition. Inline definitions are only useful when you want to have alternative versions of a function that are used depending on optimization switches, for instance.
However, I think the standard is not very clear about the inlining of external inline functions. What GCC does, for example is: non-static inline functions are not inline functions, unless they have inline and extern specifiers in the declaration (not in the external definition) of the function.
When I try to build this code
inline void f() {}
int main()
{
f();
}
using the command line
gcc -std=c99 -o a a.c
I get a linker error (undefined reference to f). The error vanishes if I use static inline or extern inline instead of just inline, or if I compile with -O (so the function is actually inlined).
This behaviour seems to be defined in paragraph 6.7.4 (6) of the C99 standard:
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.
If I understand all this correctly, a compilation unit with a function defined inline as in the above example only compiles consistently if there is also an external function with the same name, and I never know if my own function or the external function is called.
Isn't this behaviour completely daft? Is it ever useful to define a function inline without static or extern in C99? Am I missing something?
Summary of answers
Of course I was missing something, and the behaviour isn't daft. :)
As Nemo explains, the idea is to put the definition of the function
inline void f() {}
in the header file and only a declaration
extern inline void f();
in the corresponding .c file. Only the extern declaration triggers the generation of externally visible binary code. And there is indeed no use of inline in a .c file -- it's only useful in headers.
As the rationale of the C99 committee quoted in Jonathan's answer explicates, inline is all about compiler optimisations that require the definition of a function to be visible at the site of a call. This can only be achieved by putting the definition in the header, and of course a definition in a header must not emit code every time it is seen by the compiler. But since the compiler is not forced to actually inline a function, an external definition must exist somewhere.
Actually this excellent answer also answers your question, I think:
What does extern inline do?
The idea is that "inline" can be used in a header file, and then "extern inline" in a .c file. "extern inline" is just how you instruct the compiler which object file should contain the (externally visible) generated code.
[update, to elaborate]
I do not think there is any use for "inline" (without "static" or "extern") in a .c file. But in a header file it makes sense, and it requires a corresponding "extern inline" declaration in some .c file to actually generate the stand-alone code.
From the standard (ISO/IEC 9899:1999) itself:
Appendix J.2 Undefined Behaviour
...
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).
...
The C99 Committee wrote a Rationale, and it says:
6.7.4 Function specifiers
A new feature of C99: The inline keyword, adapted from C++, is a function-specifier that
can be used only in function declarations. It is useful for program optimizations that require the
definition of a function to be visible at the site of a call. (Note that the Standard does not attempt to specify the nature of these optimizations.)
Visibility is assured if the function has internal linkage, or if it has external linkage and the call
is in the same translation unit as the external definition. In these cases, the presence of the
inline keyword in a declaration or definition of the function has no effect beyond indicating a
preference that calls of that function should be optimized in preference to calls of other functions declared without the inline keyword.
Visibility is a problem for a call of a function with external linkage where the call is in a
different translation unit from the function’s definition. In this case, the inline keyword
allows the translation unit containing the call to also contain a local, or inline, definition of the
function.
A program can contain a translation unit with an external definition, a translation unit with an
inline definition, and a translation unit with a declaration but no definition for a function. Calls
in the latter translation unit will use the external definition as usual.
An inline definition of a function is considered to be a different definition than the external
definition. If a call to some function func with external linkage occurs where an inline
definition is visible, the behavior is the same as if the call were made to another function, say
__func, with internal linkage. A conforming program must not depend on which function is
called. This is the inline model in the Standard.
A conforming program must not rely on the implementation using the inline definition, nor may
it rely on the implementation using the external definition. The address of a function is always the address corresponding to the external definition, but when this address is used to call the
function, the inline definition might be used. Therefore, the following example might not
behave as expected.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Since the implementation might use the inline definition for one of the calls to saddr and use
the external definition for the other, the equality operation is not guaranteed to evaluate to 1
(true). This shows that static objects defined within the inline definition are distinct from their
corresponding object in the external definition. This motivated the constraint against even
defining a non-const object of this type.
Inlining was added to the Standard in such a way that it can be implemented with existing linker
technology, and a subset of C99 inlining is compatible with C++. This was achieved by requiring that exactly one translation unit containing the definition of an inline function be
specified as the one that provides the external definition for the function. Because that
specification consists simply of a declaration that either lacks the inline keyword, or contains
both inline and extern, it will also be accepted by a C++ translator.
Inlining in C99 does extend the C++ specification in two ways. First, if a function is declared
inline in one translation unit, it need not be declared inline in every other translation unit.
This allows, for example, a library function that is to be inlined within the library but available
only through an external definition elsewhere. The alternative of using a wrapper function for
the external function requires an additional name; and it may also adversely impact performance
if a translator does not actually do inline substitution.
Second, the requirement that all definitions of an inline function be “exactly the same” is
replaced by the requirement that the behavior of the program should not depend on whether a
call is implemented with a visible inline definition, or the external definition, of a function.
This allows an inline definition to be specialized for its use within a particular translation unit.
For example, the external definition of a library function might include some argument validation that is not needed for calls made from other functions in the same library. These
extensions do offer some advantages; and programmers who are concerned about compatibility
can simply abide by the stricter C++ rules.
Note that it is not appropriate for implementations to provide inline definitions of standard
library functions in the standard headers because this can break some legacy code that redeclares standard library functions after including their headers. The inline keyword is
intended only to provide users with a portable way to suggest inlining of functions. Because the
standard headers need not be portable, implementations have other options along the lines of:
#define abs(x) __builtin_abs(x)
or other non-portable mechanisms for inlining standard library functions.
> I get a linker error (undefined reference to f)
Works here: Linux x86-64, GCC 4.1.2. May be a bug in your compiler; I don't see anything in the cited paragraph from the standard that forbids the given program. Note the use of if rather than iff.
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.
So, if you know the behavior of the function f and you want to call it in a tight loop, you may copy-paste its definition into a module to prevent function calls; or, you may provide a definition that, for the purposes of the current module, is equivalent (but skips input validation, or whatever optimization you can imagine). The compiler writer, however, has the option of optimizing for program size instead.
If I try to compile the following C code without declaring the function static, I get a linker error:
undefined reference to '_fun'
but it works if I don't make it static. In c++, it works just fine without the static keyword.
// Doesn't work
inline int fun()
{
return 3;
}
// Works
static inline int fun()
{
return 3;
}
int main(int argc, const char * argv[])
{
printf("%i", fun());
}
The requirements for inline in C are defined by section 6.7.4 of the ISO C standard. Quoting this section from the N1256
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.
As far as I can tell, your definition satisfies all those requirements. This:
inline int fun()
{
return 3;
}
is both a declaration and a definition of fun. Without the inline keyword, it would have external linkage.
The tricky part is the last sentence:
It is unspecified whether a call to the function uses the inline
definition or the external definition.
In this case, there is no external definition. You don't say what compiler you're using, but gcc -std=c99 -pedantic apparently chooses, by default, to use the external definition, and since there isn't one, you get a linker error. (Without -std=c99 -pedantic, there's no linker error, but that's because gcc also implements inline as an extension on top of C90.)
If you're only going to be using the function in that one source file, you might as well add the static keyword anyway, to give it internal linkage.
And experiment shows that your program compiles, links, and runs correctly if I compile it with optimization, using any of -O1, -O2, or -O3.
A footnote in the C standard seems to imply that gcc is behaving correctly. An example in the same section has a similar non-static inline function definition:
inline double cels(double t)
{
return (5.0 * (t - 32.0)) / 9.0;
}
followed by:
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.
The Standard's intention seems to be that if an inline function has internal linkage, it should be defined just once in the source file that uses it, but if it has external linkage, the inline definition is an alternative to a non-inline definition that must appear elsewhere. The choice of whether to call the external function or expand the inline definition is left to the whim of the compiler.
Some points not directly relevant to your question:
int fun() should probably be int fun(void). The empty parentheses are legal, but they indicate that the function takes an unspecified number and type(s) of arguments. The void specifies that it takes no arguments, which is what you want.
You need #include <stdio.h> if you're going to call printf; this is not optional.
You don't want const in the declaration of argv. For that matter, since you don't refer to the command-line arguments, you can write int main(void).
C99 inline semantics are subtle - in fact, that whole part of the language (storage duration vs linkage, tentative and inline definitions) is a mess.
While inline acts as a compiler hint in definitions that include a storage class specifier (static or extern) and can basically be ignored, the semantics change if no specifier is present.
A definition like inline int fun(void) { ... } does two things:
First, it declares an identifier with external linkage, without providing a corresponding external definition. This means such a definition must be provided by a different translation unit or we end up with undefined behaviour (probably manifesting as failure to link).
Second, it provides an inline definition, which is an alternative to the external one. As the function body is visible in the current translation unit, the compiler may use it to inline the function or for type specialization.
To get the external definition, until fairly recently, I thought it necessary to repeat the function definition in another translation unit (or fake that with 4 lines of preprocessor code).
However, that's not necessary: A single line of code - a re-declaration of the function that includes the extern specifier - is enough to make the inline definition into an external one.
In your example, this would mean putting
inline int foo(void)
{
return 42;
}
into a header file foo.h and providing a source file foo.c with contents
#include "foo.h"
// force definition to be external instead of inline
// I believe inline could be omitted, but it doesn't hurt
extern inline foo(void);
Why is this useful? As C lacks templates, generic code normally comes with a performance penalty as you need to fake generics with void* and function pointers (or, in more complex cases, vtables).
However, a sufficiently smart optimizer can get back most (potentially all) of the performance benefits of templates, but (in the absence of link-time optimization) only if the relevant function definitions are visible in the current translation unit.
While this could be achieved by putting static definitions in headers, this might increase code size to unacceptable levels in the same way that C++ templates might.
In contrast, with a C99 inline function, the compiler is free to ignore the inline definition in favour of the external one, which could even reside in a shared library.
A good example of a function that would benefit from this is qsort(), with an inline definition in stdlib.h and an external one in libc.so. There's no a priori reason for qsort() to be slower than std::sort().
When I try to build this code
inline void f() {}
int main()
{
f();
}
using the command line
gcc -std=c99 -o a a.c
I get a linker error (undefined reference to f). The error vanishes if I use static inline or extern inline instead of just inline, or if I compile with -O (so the function is actually inlined).
This behaviour seems to be defined in paragraph 6.7.4 (6) of the C99 standard:
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.
If I understand all this correctly, a compilation unit with a function defined inline as in the above example only compiles consistently if there is also an external function with the same name, and I never know if my own function or the external function is called.
Isn't this behaviour completely daft? Is it ever useful to define a function inline without static or extern in C99? Am I missing something?
Summary of answers
Of course I was missing something, and the behaviour isn't daft. :)
As Nemo explains, the idea is to put the definition of the function
inline void f() {}
in the header file and only a declaration
extern inline void f();
in the corresponding .c file. Only the extern declaration triggers the generation of externally visible binary code. And there is indeed no use of inline in a .c file -- it's only useful in headers.
As the rationale of the C99 committee quoted in Jonathan's answer explicates, inline is all about compiler optimisations that require the definition of a function to be visible at the site of a call. This can only be achieved by putting the definition in the header, and of course a definition in a header must not emit code every time it is seen by the compiler. But since the compiler is not forced to actually inline a function, an external definition must exist somewhere.
Actually this excellent answer also answers your question, I think:
What does extern inline do?
The idea is that "inline" can be used in a header file, and then "extern inline" in a .c file. "extern inline" is just how you instruct the compiler which object file should contain the (externally visible) generated code.
[update, to elaborate]
I do not think there is any use for "inline" (without "static" or "extern") in a .c file. But in a header file it makes sense, and it requires a corresponding "extern inline" declaration in some .c file to actually generate the stand-alone code.
From the standard (ISO/IEC 9899:1999) itself:
Appendix J.2 Undefined Behaviour
...
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).
...
The C99 Committee wrote a Rationale, and it says:
6.7.4 Function specifiers
A new feature of C99: The inline keyword, adapted from C++, is a function-specifier that
can be used only in function declarations. It is useful for program optimizations that require the
definition of a function to be visible at the site of a call. (Note that the Standard does not attempt to specify the nature of these optimizations.)
Visibility is assured if the function has internal linkage, or if it has external linkage and the call
is in the same translation unit as the external definition. In these cases, the presence of the
inline keyword in a declaration or definition of the function has no effect beyond indicating a
preference that calls of that function should be optimized in preference to calls of other functions declared without the inline keyword.
Visibility is a problem for a call of a function with external linkage where the call is in a
different translation unit from the function’s definition. In this case, the inline keyword
allows the translation unit containing the call to also contain a local, or inline, definition of the
function.
A program can contain a translation unit with an external definition, a translation unit with an
inline definition, and a translation unit with a declaration but no definition for a function. Calls
in the latter translation unit will use the external definition as usual.
An inline definition of a function is considered to be a different definition than the external
definition. If a call to some function func with external linkage occurs where an inline
definition is visible, the behavior is the same as if the call were made to another function, say
__func, with internal linkage. A conforming program must not depend on which function is
called. This is the inline model in the Standard.
A conforming program must not rely on the implementation using the inline definition, nor may
it rely on the implementation using the external definition. The address of a function is always the address corresponding to the external definition, but when this address is used to call the
function, the inline definition might be used. Therefore, the following example might not
behave as expected.
inline const char *saddr(void)
{
static const char name[] = "saddr";
return name;
}
int compare_name(void)
{
return saddr() == saddr(); // unspecified behavior
}
Since the implementation might use the inline definition for one of the calls to saddr and use
the external definition for the other, the equality operation is not guaranteed to evaluate to 1
(true). This shows that static objects defined within the inline definition are distinct from their
corresponding object in the external definition. This motivated the constraint against even
defining a non-const object of this type.
Inlining was added to the Standard in such a way that it can be implemented with existing linker
technology, and a subset of C99 inlining is compatible with C++. This was achieved by requiring that exactly one translation unit containing the definition of an inline function be
specified as the one that provides the external definition for the function. Because that
specification consists simply of a declaration that either lacks the inline keyword, or contains
both inline and extern, it will also be accepted by a C++ translator.
Inlining in C99 does extend the C++ specification in two ways. First, if a function is declared
inline in one translation unit, it need not be declared inline in every other translation unit.
This allows, for example, a library function that is to be inlined within the library but available
only through an external definition elsewhere. The alternative of using a wrapper function for
the external function requires an additional name; and it may also adversely impact performance
if a translator does not actually do inline substitution.
Second, the requirement that all definitions of an inline function be “exactly the same” is
replaced by the requirement that the behavior of the program should not depend on whether a
call is implemented with a visible inline definition, or the external definition, of a function.
This allows an inline definition to be specialized for its use within a particular translation unit.
For example, the external definition of a library function might include some argument validation that is not needed for calls made from other functions in the same library. These
extensions do offer some advantages; and programmers who are concerned about compatibility
can simply abide by the stricter C++ rules.
Note that it is not appropriate for implementations to provide inline definitions of standard
library functions in the standard headers because this can break some legacy code that redeclares standard library functions after including their headers. The inline keyword is
intended only to provide users with a portable way to suggest inlining of functions. Because the
standard headers need not be portable, implementations have other options along the lines of:
#define abs(x) __builtin_abs(x)
or other non-portable mechanisms for inlining standard library functions.
> I get a linker error (undefined reference to f)
Works here: Linux x86-64, GCC 4.1.2. May be a bug in your compiler; I don't see anything in the cited paragraph from the standard that forbids the given program. Note the use of if rather than iff.
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.
So, if you know the behavior of the function f and you want to call it in a tight loop, you may copy-paste its definition into a module to prevent function calls; or, you may provide a definition that, for the purposes of the current module, is equivalent (but skips input validation, or whatever optimization you can imagine). The compiler writer, however, has the option of optimizing for program size instead.