Lately I have been making an attempt to read more open source C code. A common pattern that I have been adopting in my hobby projects is as follows.
In my C files, I have functions that are either static or exported. Only functions that are exported are placed in a header file. Global variables which are only used within the scope of an object are also used as static global variables.
My question concerns the usefulness and motivation of having static inline functions inside header files. From what I read online, not using the static keyword causes a multiple definition error and that is the reason for not just defining the function as just inline.
However, does this mean that this function is exported for other objects to use?
If yes, then why not just defining this function in the C file and export it via the header file?
If not, why putting this in the header file rather than just having it inside the C file?
Is there a reason behind this coding style? What am I missing?
One such example can be found in the git codebase inside hashmap.h:
/*
* Converts a cryptographic hash (e.g. SHA-1) into an int-sized hash code
* for use in hash tables. Cryptographic hashes are supposed to have
* uniform distribution, so in contrast to `memhash()`, this just copies
* the first `sizeof(int)` bytes without shuffling any bits. Note that
* the results will be different on big-endian and little-endian
* platforms, so they should not be stored or transferred over the net.
*/
static inline unsigned int sha1hash(const unsigned char *sha1)
{
/*
* Equivalent to 'return *(unsigned int *)sha1;', but safe on
* platforms that don't support unaligned reads.
*/
unsigned int hash;
memcpy(&hash, sha1, sizeof(hash));
return hash;
}
A static inline function is, in practice, likely (but not certain) to be inlined by some good optimizing compiler (e.g. by GCC when it is given -O2) at most of its call sites.
It is defined in a header file, because it then could be inlined at most call sites (perhaps all of them). If it was just declared (and simply "exported") the inlining is unlikely to happen (except if you compile and link with link-time optimizations, a.k.a. LTO, also, e.g. compile and link with gcc -flto -O2, and that increases a lot the build time).
In practice, the compiler needs to know the body of a function to be able to inline it. So a suitable place is to define it in some common header file (otherwise, it could be inlined only in the same translation unit defining it, unless you enable LTO), so that every translation unit would know the body of that inlinable function.
It is declared static to avoid multiple definitions (at link time) in case the compiler did not inline it (e.g. when you use its address).
In practice, in C99 or C11 code (except with LTO, which I rarely use), I would always put the short functions I want to be inlined as static inline definitions in common header files.
Be sure to understand how and when the C preprocessor works. Notice that you could in principle (but it would be very bad practice and disgusting style) avoid defining some static inline function in a common header file and instead copy and paste its identical definition in multiple .c files.
(However, that might make sense for generated .c files, e.g. if you design a compiler emitting C code).
FYI LTO is practically implemented by recent GCC compilers by embedding some internal compiler representation (some GIMPLE) inside object files, and redoing some "compilation" step - using the lto1 frontend - at "link" time. In practice, the entire program is almost compiled "twice".
(actually, I always wondered why the C standardization committee did not decide instead that all explicitly inline functions are static)
Related
I have heard that, when you have just 1 (main.c) file (or use a "unity build"), there are benefits to be had if you make all your functions static.
I am kind of confused why this (allegedly) isn't optimized by default, since it's not probable that you will include main.c into another file where you will use one of its functions.
I would like to know the benefits and dangers of doing this before implementing it.
Example:
main.c
static int my_func(void){ /*stuff*/ }
int main(void) {
my_func();
return 0;
}
You have various chunks of wisdom in the comments, assembled here into a Community Wiki answer.
Jonathan Leffler noted:
The primary benefit of static functions is that the compiler can (and will) aggressively inline them when it knows there is no other code that can call the function. I've had error messages from four levels of inlined function calls (three qualifying “inlined from” lines) on occasion. It's staggering what a compiler will do!
and:
FWIW: my rule of thumb is that every function should be static until it is known that it will be called from code in another file. When it is known that it will be used elsewhere, it should be declared in a header file that is included both where the function is defined and where it is used. (Similar rules apply to file scope variables — aka 'global variables'; they should be static until there's a proven need for them elsewhere, and then they should be declared in a header too.)
The main() function is always called from the startup code, so it is never static. Any function defined in the same file as an unconditionally compiled main() function cannot be reused by other programs. (Library code might contain a conditionally compiled test program for the library function(s) defined in the source file — most of my library code has #ifdef TEST / …test program… / #endif at the end.)
Eirc Postpischil generalized on that:
General rule: Anytime you can write code that says the use of something is limited, do it. Value will not be modified? Make it const. Name only needs to be used in a certain section? Declare it in the innermost enclosing scope. Name does not need to be linked externally? Make it static. Every limitation both shrinks the window for a bug to be created and may remove complications that interfere with optimization.
I am reading through Linux v3.19's implementation of PID namespaces and in pid_namespace.h there are functions defined that are redefined in pid_namespace.c. For example, in pid_namespace.h there is the following definition:
static inline struct pid_namespace *copy_pid_ns(unsigned long flags,
struct user_namespace *user_ns, struct pid_namespace *ns)
{
if (flags & CLONE_NEWPID)
ns = ERR_PTR(-EINVAL);
return ns;
}
And then in pid_namespace.c there is a second copy_pid_ns definition:
struct pid_namespace *copy_pid_ns(unsigned long flags,
struct user_namespace *user_ns, struct pid_namespace *old_ns)
{
if (!(flags & CLONE_NEWPID))
return get_pid_ns(old_ns);
if (task_active_pid_ns(current) != old_ns)
return ERR_PTR(-EINVAL);
return create_pid_namespace(user_ns, old_ns);
}
What does this re-defining achieve? Why is it done? Thanks for your help!
These two definitions corresponds to two incompatible configurations:
Definition of copy_pid_ns in the include/linux/pid_namespace.h#L76 header is parsed only with CONFIG_PID_NS option disabled (see line 68 in that header).
The file kernel/pid_namespace.c is compiled only with CONFIG_PID_NS option enabled (it can be found from kernel/Makefile). For that configuration the header contains just a declaration of the function at line 62.
Situation when the header file declares some function twice is quite natural for the Linux kernel sources:
One declaration (without definition) corresponds to some functionality being enabled. In that configuration the function is defined in some source file which is compiled only with functionality being enabled.
Another declaration is a definition of static inline function and corresponds to disabled functionality.
Note
The question omits relevant information from the source code repository it extracted the source code from, so the answer below does not apply to the source code in those files. It appears at most one of the two definitions is selected based on build options, so they are not both used in the same build.
Old Answer Regarding static inline
The version in the header is marked static inline. In this declaration, static causes the name copy_pid_ns to have internal linkage, meaning the definition here will apply only to uses of copy_pid_ns in the current translation unit (the source file being compiled, including the files it includes). The idea of inline is that this function is so small, it would be good if, wherever it is called, the compiler just wrote the code for it in place of the call instead of actually using a subroutine call instruction for the function. (Technically inline is just a suggestion to the compiler in this regard. Good modern compilers mostly make their own decisions about which functions to inline.)
Because the definition in the header is static inline, it is not accessible to other translation units. The definition in the other source file has external linkage, meaning any uses of copy_pid_ns in other translation units can be linked to it (if they do not have their own private static version). Those uses in other translation units will have to use actual subroutine call instructions to call this function.
Providing an external version is not necessary if all uses of copy_pid_ns have the static version available, but one may be provided because that is not always the case or just as a safety fallback.
First look at qualifiers in front of the function:
static inline... -> static will be resolved only in included source files (*.c, *.cpp)
like private qualifier, inline will replace directly this function instead accessing it as reference
have no qualifiers -> more like a public external function. If you define your usage of the function as extern you should compile (*.c) file which contains implementation of the function and then the linker will resolve your call to the function as reference.
It's not a redefinition. The key to realizing what's intended here is the presence of static qualifier for the first definition, and knowing how programs are built with C. Also, inline is seldom used without static, at least with C89 and GNU extensions which is what is used to compile Linux, but inline in and out of itself doesn't play a role here.
The static inline definition in pid_namespace.h is only visible to the translation unit (.c file) that includes that header file, directly or indirectly. The static qualifier is what restricts this visibility. If you include pid_namespace.h from another translation unit, that translation unit will have its own, another copy of the function. Each object file will have its own copy of the function definition, available only to itself. Additionally, because of the inline qualifier, the function may not even exist as such because the compiler is free to "inline" it.
The second definition does not have a static qualifier and can thus be used by other translation units that do not themselves contain it. The C compiler compiles object files from their respective translation units, and the linker links these object files together and produces a program image where references to said definition are correctly resolved. The compiler does not care if more than one translation unit embed the same function -- to it they're just object files it needs to compile one by one. But the linker will abort because it isn't designed to have to choose between such multiple definitions in its input.
In practice, there is many ways this can be used. The former definition may be the short version used in kernel mode (privileged kernel code), while the latter is used in user mode, as result of processing a system call, for example.
In general, defining procedures several times is permitted as long as there is at most one object available to the linker (in case it needs to resolve references to the function, like function calls). You can juggle your .c and .h files however you like, as long as that requirement holds. If you also know how to use static and inline qualifiers, you can add definitions that are not externally visible (static) and benefit from compiler being able to inline them.
This question already has answers here:
C: Why do we include header files, which declare but don't define?
(5 answers)
Closed 4 years ago.
This is the question I still cannot answer by myself (probably due to lack of experience in C).
So I found this answer and the question is what's wrong with putting definitions into a header files? I we don't declare them as static it should be fine since they will have external linkage and linker will not complain.
Secondly, why should not we put static definition into a header file? Suppose we want to make some function sort of "compilation-unit private" that is not intended to have external linkage.
And what I was surprised about was why is it (rarely) possible to put inline function definition into header files?
Is it just by convention only?
There is not usually any point in putting information into a header unless it will be included in multiple other source files. That means that if the header defines some variables, each source file that includes the header will define those variables. And it is normally an error to define the same (global) variable more than once. So, putting variable definitions into a header normally defeats the reason for creating a header in the first place.
Note that C does have a 'one definition rule', similar to C++, but not as strong. There is a 'common' extension — complete with double entendre — that often allows you to get away with defining a variable in more than one file, but it doesn't work if the variable has a non-trivial initialization.
You can find a lot of information in How do I use extern to share variables between source files?, including information about the common extension.
You should not normally define static variables in a header because that means that each file that includes the header will define its own copy of the variables. This is usually not what's wanted. It tends to make programs bigger.
If you reliably work with compilers that support inline, there is no particular reason why you can't put static inline function definitions into a header. There is a risk that if the function cannot be inlined, then the compiler will generate a static function in the object code for each source file that uses the function, again increasing the size of the executable. You might be able to avoid that by using non-static inline function definitions. If the functions are small enough that they will be inlined, there is no particular reason not to put them in a header.
You can find more information about inline functions, with static or extern, in the Q&A on Stack Overflow:
extern inline
Is inline without static or extern ever useful in C99
What's the difference between static and static inline functions?
Note the rather extensive use of weasel words such as 'usually' and 'normally' in the answer above. You can, with care, find exceptional situations that warrant breaking the rules, but if you remember that headers are the glue that provide cross-checking between the code that uses some functionality (types, constants, functions, sometimes variables) and the code that implements the functionality, then you'll realize that it is good to follow these rules:
Headers declare types, constants, enumerations, functions, variables that are used by multiple source files.
Source files implement functions and define variables that are used by multiple source files.
The header files are used by the implementation code to ensure that the implementation matches the specification.
The header files are used by the consumer code to follow the source-level rules for the implementation.
Header files should not define variables.
Source files should not declare external variables; they should include the relevant header.
Headers may sensibly define static inline functions; you may even include plain inline function definitions in a header, but you have to be careful to instantiate the functions somewhere in case they are not inlined — and that's when extern inline comes into play. (Be aware that old GCC rules for inline functions are different from C99 standard rules.)
There are some rules that simply including a header won't enforce, such as required sequences for calling functions (don't call a free function before the corresponding allocate function, for example). But using headers wisely prevents a lot of errors.
See also:
Should I use #include in headers?
How to link multiple implementation files in C?
And many other questions, no doubt.
I defined my function in .c (without header declaration) as here:
inline int func(int i) {
return i+1;
}
Then in the same file below I use it:
...
i = func(i);
And during the linking I got "undefined reference to 'func'". Why?
The inline model in C99 is a bit different than most people think, and in particular different from the one used by C++
inline is only a hint such that the compiler doesn't complain about doubly defined symbols. It doesn't guarantee that a function is inlined, nor actually that a symbol is generated, if it is needed. To force the generation of a symbol you'd have to add a sort of instantiation after the inline definition:
int func(int i);
Usually you'd have the inline definition in a header file, that is then included in several .c files (compilation units). And you'd only have the above line in exactly one of the compilation units. You probably only see the problem that you have because you are not using optimization for your compiler run.
So, your use case of having the inline in the .c file doesn't make much sense, better just use static for that, even an additional inline doesn't buy you much.
C99 inline semantics are often misunderstood. The inline specifier serves two purposes:
First, as a compiler hint in case of static inline and extern inline declarations. Semantics remain unchanged if you remove the specifier.
Second, in case of raw inline (ie without static or extern) to provide an inline definition as an alternative to an external one, which has to be present in a different translation unit. Not providing the external one is undefined behaviour, which will normally manifest as linking failure.
This is particularly useful if you want to put a function into a shared library, but also make the function body available for optimization (eg inlining or specialization). Assuming a sufficiently smart compiler, this allows you to recover many of the benefits of C++ templates without having to jump through preprocessor hoops.
Note that it's a bit more messy than I described here as having another file scope non-inline external declaration will trigger the first case as described in Jens' answer, even if the definition itself is inline instead of extern inline. This is by design so you can have have a single inline definition in a header file, which you can include into the source file that provides the external one by adding a single line for the external declaration.
This is because of the way GCC handle inline function. GCC performs inline substitution as the part of optimization.
To remove this error use static before inline. Using static keyword force the compiler to inline this function, which makes the program compile successfully.
static inline int func(int i) {
return i+1;
}
...
i = func(i);
I read several questions in stackoverflow about inline in C but still am not clear about it.
static inline void f(void) {} has no practical difference with static void f(void) {}.
inline void f(void) {} in C doesn't work as the C++ way. How does it work in C?
What actually does extern inline void f(void); do?
I never really found a use of the inline keyword in my C programs, and when I see this keyword in other people's code, it's almost always static inline, in which I see no difference with just static.
A C code can be optimized in two ways: For Code size and for Execution Time.
inline functions:
gcc.gnu.org says,
By declaring a function inline, you can direct GCC to make calls to that function faster. One way GCC can achieve this is to integrate that function's code into the code for its callers. This makes execution faster by eliminating the function-call overhead; in addition, if any of the actual argument values are constant, their known values may permit simplifications at compile time so that not all of the inline function's code needs to be included. The effect on code size is less predictable; object code may be larger or smaller with function inlining, depending on the particular case.
So, it tells the compiler to build the function into the code where it is used with the intention of improving execution time.
If you declare Small functions like setting/clearing a flag or some bit toggle which are performed repeatedly, inline, it can make a big performance difference with respect to time, but at the cost of code size.
non-static inline and Static inline
Again referring to gcc.gnu.org,
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.
extern inline?
Again, gcc.gnu.org, says it all:
If you specify both inline and 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.
This combination of inline and extern has almost the effect of a macro. The way to use it is to put a function definition in a header file with these keywords, and put another copy of the definition (lacking inline and extern) in a library file. The definition in the header file causes most calls to the function to be inlined. If any uses of the function remain, they refer to the single copy in the library.
To sum it up:
For inline void f(void){},
inline definition is only valid in the current translation unit.
For static inline void f(void) {}
Since the storage class is static, the identifier has internal linkage and the inline definition is invisible in other translation units.
For extern inline void f(void);
Since the storage class is extern, the identifier has external linkage and the inline definition also provides the external definition.
Note: when I talk about .c files and .h files in this answer, I assume you have laid out your code correctly, i.e. .c files only include .h files. The distinction is that a .h file may be included in multiple translation units.
static inline void f(void) {} has no practical difference with static void f(void) {}.
In ISO C, this is correct. They are identical in behaviour (assuming you don't re-declare them differently in the same TU of course!) the only practical effect may be to cause the compiler to optimize differently.
inline void f(void) {} in C doesn't work as the C++ way. How does it work in C? What actually does extern inline void f(void); do?
This is explained by this answer and also this thread.
In ISO C and C++, you can freely use inline void f(void) {} in header files -- although for different reasons!
In ISO C, it does not provide an external definition at all. In ISO C++ it does provide an external definition; however C++ has an additional rule (which C doesn't), that if there are multiple external definitions of an inline function, then the compiler sorts it out and picks one of them.
extern inline void f(void); in a .c file in ISO C is meant to be paired with the use of inline void f(void) {} in header files. It causes the external definition of the function to be emitted in that translation unit. If you don't do this then there is no external definition, and so you may get a link error (it is unspecified whether any particular call of f links to the external definition or not).
In other words, in ISO C you can manually select where the external definition goes; or suppress external definition entirely by using static inline everywhere; but in ISO C++ the compiler chooses if and where an external definition would go.
In GNU C, things are different (more on this below).
To complicate things further, GNU C++ allows you to write static inline an extern inline in C++ code... I wouldn't like to guess on what that does exactly
I never really found a use of the inline keyword in my C programs, and when I see this keyword in other people's code, it's almost always static inline
Many coders don't know what they're doing and just put together something that appears to work. Another factor here is that the code you're looking at might have been written for GNU C, not ISO C.
In GNU C, plain inline behaves differently to ISO C. It actually emits an externally visible definition, so having a .h file with a plain inline function included from two translation units causes undefined behaviour.
So if the coder wants to supply the inline optimization hint in GNU C, then static inline is required. Since static inline works in both ISO C and GNU C, it's natural that people ended up settling for that and seeing that it appeared to work without giving errors.
, in which I see no difference with just static.
The difference is just in the intent to provide a speed-over-size optimization hint to the compiler. With modern compilers this is superfluous.
From 6.7.4 Function specifiers in C11 specs
6 A function declared with an inline function specifier is an inline
function. Making a function an inline function suggests that calls to
the function be as fast as possible.138)The extent to which
such suggestions are effective is
implementation-defined.139)
138) By using, for example, an alternative to the usual function call
mechanism, such as inline substitution. Inline substitution is not
textual substitution, nor does it create a new function. Therefore,
for example, the expansion of a macro used within the body of the
function uses the definition it had at the point the function body
appears, and not where the function is called; and identifiers refer
to the declarations in scope where the body occurs. Likewise, the
function has a single address, regardless of the number of inline
definitions that occur in addition to the external
definition.
139) For example, an implementation might
never perform inline substitution, or might only perform inline
substitutions to calls in the scope of an inline declaration.
It suggests compiler that this function is widely used and requests to prefer speed in invocation of this function. But with modern intelligent compiler this may be more or less irrelevant as compilers can decide whether a function should be inlined and may ignore the inline request from users, because modern compilers can very effectively decide about how to invoke the functions.
static inline void f(void) {} has no practical difference with static
void f(void) {}.
So yes with modern compilers most of the time none. With any compilers there are no practical / observable output differences.
inline void f(void) {} in C doesn't work as the C++ way. How does it
work in C?
A function that is inline anywhere must be inline everywhere in C++ and linker does not complain multiple definition error (definition must be same).
What actually does extern inline void f(void); do?
This will provide external linkage to f. Because the f may be present in other compilation unit, a compiler may choose different call mechanism to speed up the calls or may ignore the inline completely.
A function where all the declarations (including the definition) mention inline and never extern.
There must be a definition in the same translation unit. The standard refers to this as an inline definition.
No stand-alone object code is emitted, so this definition can't be called from another translation unit.
In this example, all the declarations and definitions use inline but not extern:
// a declaration mentioning inline
inline int max(int a, int b);
// a definition mentioning inline
inline int max(int a, int b) {
return a > b ? a : b;
}
Here is a reference which can give you more clarity on the inline functions in C & also on the usage of inline & extern.
If you understand where they come from then you'll understand why they are there.
Both "inline" and "const" are C++ innovations that were eventually retrofit into C. One of the design goals implicit in these innovations, as well as later innovations, like template's and even lambda's, was to carve out the most common use-cases for the pre-processor (particularly, of "#define"), so as to minimize the use of and need for the pre-processor phase.
The occurrence of a pre-processor phase in a language severely limits the ability to provide transparency in the analysis of and translation from a language. This turned what ought to have been easy translation shell scripts into more complicated programs, such as "f2c" (Fortran to C) and the original C++ compiler "cfront" (C++ to C); and to a lesser degree, the "indent" utility. If you've ever had to deal with the translation output of convertors like these (and we have) or with actually making your own translators, then you'll know how much of an issue this is.
The "indent" utility, by the way, balks on the whole issue and just wings it, compromising by just treating macros calls as ordinary variables or function calls, and passing over "#include"'s. The issue will also arise with other tools that may want to do source-to-source conversion/translation, like automated re-engineering, re-coding and re-factoring tools; that is, things that more intelligently automate what you, the programmer, do.
So, the ideal is to reduce dependency on the pre-processor phase to a bare minimum. This is a goal that is good in its own right, independently of how the issue may have been encountered in the past.
Over time, as more and more of the use-cases became known and even standardized in their usage, they were encapsulated formally as language innovations.
One common use-case of "#define" to create manifest constants. To a large extent, this can now be handled be the "const" keyword and (in C++) "constexpr".
Another common use-case of "#define" is to create functions with macros. Much of this is now encapsulated by the "inline" function, and that's what it's meant to replace. The "lambda" construct takes this a step further, in C++.
Both "const" and "inline" were present in C++ from the time of its first external release - release E in February 1985. (We're the ones who transcribed and restored it. Before 2016, it only existed as a badly-clipped printout of several hundred pages.)
Other innovations were added later, like "template" in version 3.0 of cfront (having been accepted in the ANSI X3J16 meeting in 1990) and the lambda construct and "constexpr" much more recently.
As the word "Inline" say "In" "Line", adding this keyword to a function affects the program in runtime, when a program is compiled, the code written inside a function is pasted under the function call, as function calls are more costly than inline code, so this optimizes the code.
So, static inline void f(void) {} and static void f(void) {}, here the inline keyword does make a difference in runtime. But when the function has too many lines of code then it won't affect runtime.
If you add static before a function, the function's lifetime is the lifetime of the whole program. And that function use is restricted to that file only.
To know about extern you can refer to - Effects of the extern keyword on C functions