Compiler/Linking Error: Freedup - c

I've been trying to compile a program for hardlinking duplicate files called freedup. I did try to email the author/maintainer of the program, but it's been a long time and I haven't heard anything back from him.
I'm trying to compile the program from a cygwin environment using the latest stable versions of gcc (3.4.4-999) and make (3.81-2). I've tried deleting all the object files and running make, but I always get the following error:
freedup.o: In function 'main':
/home/[user]/freedup-1.5/freedup.c:1791: undefined reference to '_hashed'
collect2: ld returned 1 exit status
make: * * * [freedup] Error 1
I did take a look at the source code and saw that the "hashed" function is an inline function (which I didn't think had to be declared outside of the source file... but that's just what I gathered from some preliminary googling).
If anyone would be kind enough to try compiling this program in a windows environment and has any luck, I'd really appreciate it. Thanks
The direct link for the source files is: http://freedup.org/freedup-1.5-3-src.tgz

I'm not impressed by code that uses '#include <linux/stat.h>' instead of '#include <sys/stat.h>'. I'm also unimpressed by code where the version.h file contains:
-e #define VERSION "1.5-3"
(That file is generated by a command - 'echo -e '#define...' > version.h'. Ugh!)
If you change the function from:
inline int hashed(const char*s)
{
int returnval=atoi(s);
if(returnval>2) returnval=2;
if(returnval<0) returnval=0;
return returnval;
}
to:
static
inline int hashed(const char*s)
{
int returnval=atoi(s);
if(returnval>2) returnval=2;
if(returnval<0) returnval=0;
return returnval;
}
(and fix the other problems alluded to above), then it compiles on MacOS X 10.6.2 with GCC
"i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5646) (dot 1)".
The test code fails at random points since it assumes the touch in /bin/touch (it is /usr/bin/touch on MacOS X). There are also many warnings about 'type qualifiers ignored on function return type' because 'auto.h' defines 4 functions as returning 'const int' (for various guises of 'int'), and also in function pointers in a structure in the same header.
I guess this comes down to insufficient experience on the part of the authors - or insufficient platforms tested. The version.h command does not need to use a tab (I believe the '-e' is to expand the '\t' notation in the command line - the Makefile should be fixed to omit the '-e' and replace the '\t' with a simple blank.
The behaviour of 'inline' in standard C99 is interesting:
6.7.4 Function specifiers
Syntax
function-specifier:
inline
Constraints
Function specifiers shall be used only in the declaration of an identifier for a function.
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.
In a hosted environment, the inline function specifier shall not appear in a declaration
of main.
Semantics
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.118) The extent to which such suggestions are effective is
implementation-defined.119)
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.120)
118) 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.
119) For example, an implementation might never perform inline substitution, or might only perform inline
substitutions to calls in the scope of an inline declaration.
120) 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.

Jonathan Leffler provides the answer for freedup 1.5.3: add 'static' or remove 'inline' on the hashed function. (You should probably accept that answer.)
freedup 1.6-* doesn't compile on Cygwin at all:
socket.c:20:26: fatal error: net/ethernet.h: No such file or directory
This file doesn't exist in Cygwin.

Related

Global singleton in header-only C library

I am trying to implement a global singleton variable in the header-only library in C (not C++). So after searching on this forum and elsewhere, I came across a variation of Meyer's singleton that I am adapting to C here:
/* File: sing.h */
#ifndef SING_H
#define SING_H
inline int * singleton()
{
static int foo = 0;
return &foo;
}
#endif
Notice that I am returning a pointer because C lacks & referencing available in C++, so I must work around it.
OK, now I want to test it, so here is a simple test code:
/* File: side.h */
#ifndef SIDE_H
#define SIDE_H
void side();
#endif
/*File: side.c*/
#include "sing.h"
#include <stdio.h>
void side()
{
printf("%d\n",*(singleton()));
}
/*File: main.c*/
#include "sing.h"
#include "side.h"
#include <stdio.h>
int main(int argc, char * argv[])
{
/* Output default value - expected output: 0 */
printf("%d\n",*(singleton()));
*(singleton()) = 5;
/* Output modified value - expected output: 5 */
printf("%d\n",*(singleton()));
/* Output the same value from another module - expected output: 5*/
side();
return 0;
}
Compiles and runs fine in MSVC in C mode (also in C++ mode too, but that's not the topic). However, in gcc it outputs two warnings (warning: ‘foo’ is static but declared in inline function ‘singleton’ which is not static), and produces an executable which then segfaults when I attempt to run it. The warning itself kind of makes sense to me (in fact, I am surprised I don't get it in MSVC), but segfault kind of hints at the possibility that gcc never compiles foo as a static variable, making it a local variable in stack and then returns expired stack address of that variable.
I tried declaring the singleton as extern inline, it compiles and runs fine in MSVC, results in linker error in gcc (again, I don't complain about linker error, it is logical).
I also tried static inline (compiles fine in both MSVC and gcc, but predictably runs with wrong output in the third line because the side.c translation unit now has its own copy of singleton.
So, what am I doing wrong in gcc? I have neither of these problems in C++, but I can't use C++ in this case, it must be straight C solution.
I could also accept any other form of singleton implementation that works from header-only library in straight C in both gcc and MSVC.
I am trying to implement a global singleton variable in the header-only library in C (not C++).
By "global", I take you to mean "having static storage duration and external linkage". At least, that's as close as C can come. That is also as close as C can come to a "singleton" of a built-in type, so in that sense, the term "global singleton" is redundant.
Notice that I am returning a pointer because C lacks & referencing available in C++, so I must work around it.
It is correct that C does not have references, but you would not need either pointer or reference if you were not using a function to wrap access to the object. I'm not really seeing what you are trying to gain by that. You would likely find it easier to get what you are looking for without. For example, when faced with duplicate external defintions of the same variable identifier, the default behavior of all but the most recent versions of GCC was to merge them into a single variable. Although current GCC reports this situation as an error, the old behavior is still available by turning on a command-line switch.
On the other hand, your inline function approach is unlikely to work in many C implementations. Note especially that inline semantics are rather different in C than in C++, and external inline functions in particular are rarely useful in C. Consider these provisions of the C standard:
paragraph 6.7.4/3 (a language constraint):
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.
Your example code is therefore non-conforming, and conforming compilers are required to diagnose it. They may accept your code nonetheless, but they may do anything they choose with it. It seems unreasonably hopeful to expect that you could rely on a random conforming C implementation to both accept your code for the function and compile it such that callers in different translation units could obtain pointers to the same object by calling that function.
paragraph 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 [...], somewhere in the entire program there shall be exactly one external definition for the identifier [...].
Note here that although an inline definition of a function identifier with external linkage -- such as yours -- provides an external declaration of that identifier, it does not provide an external definition of it. This means that a separate external definition is required somewhere in the program (unless the function goes altogether unused). Moreover, that external definition cannot be in a translation unit that includes the inline definition. This is large among the reasons that extern inline functions are rarely useful in C.
paragraph 6.7.4/7:
For a function with external linkage, the following restrictions apply: [...] 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.
In addition to echoing part of 6.9/5, that also warns you that if you do provide an external definition of your function to go with the inline definitions, you cannot be sure which will be used to serve any particular call.
Furthermore, you cannot work around those issues by declaring the function with internal linkage, for although that would allow you to declare a static variable within, each definition of the function would be a different function. Lest there be any doubt, Footnote 140 clarifies that in that case,
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.
(Emphasis added.)
So again, the approach presented in your example cannot be relied upon to work in C, though you might find that in practice, it does work with certain compilers.
If you need this to be a header-only library, then you can achieve it in a portable manner by placing an extra requirement on your users: exactly one translation unit in any program using your header library must define a special macro before including the header. For example:
/* File: sing.h */
#ifndef SING_H
#define SING_H
#ifdef SING_MASTER
int singleton = 0;
#else
extern int singleton;
#endif
#endif
With that, the one translation unit that defines SING_MASTER before including sing.h (for the first time) will provide the needed definition of singleton, whereas all other translation units will have only a declaration. Moreover, the variable will be accessible directly, without either calling a function or dereferencing a pointer.

Undefined Reference when using inline functions in C [duplicate]

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.

Why does inline void foo() { ... } in a common header just work?

Consider the use of inline in C99, with various options (extern'ing, static inline etc), as described here, for example.
I don't understand why the C standard does not allow for just using
void inline foo() { do_stuff(); }
in a common header file, and for that to work everywhere. Why do I have to add static? Isn't what I want clear enough already?
From the gcc site:
When an inline function is not static, then the compiler must assume
that there may be calls from other source files; since a global symbol
can be defined only once in any program, the function must not be
defined in the other source files, so the calls therein cannot be
integrated. Therefore, a non-static inline function is always compiled
on its own in the usual fashion.
What does it mean for you. You cannot define the inline function in the header since it will mean that it will be defined from different translation units (.c files that include it).
Once it is defined static inline then each c file that includes the header will have its own copy of the function.
EDIT
gcc behaves correctly. Inline functions were added to the standard with the introduction of C99. The standard is somewhat ambiguous and states:
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.
What it actually means is that when the compiler sees the inline keyword cannot know if the function was already defined in another translation unit (This will be known only during linking). Now most compilers gcc included will not inline a function without optimizations turned on. So if you try to use an inline function when compiling with -O0 the compiler issues a real call to the function (It assumes it is defined in a another file then the one it is currently compiling). Now when the linker encounters the call it tries to find the function in all compiled objects but fails (because the compiler didn't create a body for the function neither did it inline it - the standard says it doesn't have to create a body for the function and that it can assume there is a definition some where). This is why you get the error: undefined reference to f when you link your project. This is the correct behavior when compiling with -std=c99 onward. It also means that if you want an inline function to have abody you must declare it external only once BUT you must also provide the definition within the same translation unit you declared the function with extrnal linkage.
So in order to get your code to work correctly according to the standard you should do the following:
in the h file just do as you would expect.
inline void f(){ /*DO SOMETHING*/}
And in just one of your code files (.c files) you do:
extern inline void f();
What happens is that now the compiler encounters in just one translation unit both body definition (taken from the header) and a declaration that says it should exist an external definition somewhere and in accordance with the standard creates one for the function.
So the standard says that any function with internal linkage can be declared inline and that the compiler should generate a body for it. In C a function is considered to have internal linkage only when adding the static keyword.
This is why static inline void f() works. Without the static keyword the compiler assumes that the function has external linkage and that is why just specifying inline void f() without also adding extern inline void f() in just one source file will not work.
...C standard does not allow for just using...
That's completely wrong. Your question is based on some incorrect/outdated/compiler specific premise, which has nothing to do with C standard. In C language you don't need static when putting inline function in header file. An inline definition without an explicitly specified extern keyword does not form an external definition for that function. For that reason inline definition without static cannot trigger any multiple-definition-related errors (if that's what you are afraid of).
Moreover, the link that you posted clearly says that C standard does not say anything implied in your question. It says that GCC compiler implements inline differently from what's required by C standard (probably referring to an older version of GCC).
In other words, from C language point of view you can (and should) put
inline void foo() { do_stuff(); }
in the header file. No static required.

Why is static keyword required for inline function?

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

Is "inline" without "static" or "extern" ever useful in C99?

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.

Categories

Resources