Static inline functions in header file

Recently, I have been trying to read more open source C code. The general scheme that I used in my hobby projects is as follows.

My C files have functions that are static or exportable. Only exported functions are placed in the header file. Global variables that are used only within an object are also used as static global variables.

My question is about the usefulness and motivation for having static inline functions inside header files. From what I read on the Internet, static keyword causes a multiple definition error, and this is not the reason for just defining a function as just inline .

However, does this mean that this function is exported for use by other objects? If so, why not just define this function in the C file and export it through the header file? If not, why put this in a header file and not just put it in a C file?

Is there a reason for this coding style? What am I missing?

One such example can be found in the hashmap.h git database inside hashmap.h :

 /* * Converts a cryptographic hash (eg 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; } 
+9
source share
1 answer

static inline function, in practice, is likely (but not necessarily) to be built in by some good optimizing compiler (for example, GCC when it is given -O2 ) on most of its call sites.

It is defined in the header file because it can be embedded on most call sites (possibly all). If it was just declared (and simply “exported”), then embedding is unlikely to happen (unless you compile and link to optimizations during linking , also known as LTO, for example, they compile and link to gcc -flto -O2 , and this significantly increases assembly time).

In practice, the compiler must know the body of the function in order to be able to embed it. Thus, a suitable place is to define it in some common header file (otherwise it can only be embedded in the same translation unit that defines it if you do not enable LTO) so that each translation unit knows the body of this built-in function.

It is declared static order to avoid several definitions (at the time of reference) in case the compiler did not enable it (for example, when you use its address).

In practice, in C99 or C11 code (with the exception of LTO, which I rarely use), I would always put short functions that I want to embed, like static inline definitions in shared header files.

Be sure to understand how and when the C preprocessor works . Note that you can, in principle (but that would be a 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 into multiple .c files. (However, this may make sense for the generated .c files, for example, if you are developing a compiler that emits C code ).

FYI LTO is practically implemented by recent GCC compilers, embedding some internal compiler representation (a bit of GIMPLE ) in object files and redoing some “compilation” step - using the lto1 interface - during the “link”. In practice, the entire program is practically compiled “twice”.

(in fact, I always wondered why the C standardization committee did not decide instead that all explicitly inline functions are static)

+14
source

Source: https://habr.com/ru/post/1274073/


All Articles