Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why declare a C function as static inline?

Tags:

c

objective-c

I came across an example for a C-function declared as:

static inline CGPoint SOCGPointAdd(const CGPoint a, const CGPoint b) {
    return CGPointMake(a.x + b.x, a.y + b.y);
}

Until now, I declared utility C-functions in .h files and implemented them in .m files, just like this:

CGPoint SOCGPointAdd(const CGPoint a, const CGPoint b) {
    return CGPointMake(a.x + b.x, a.y + b.y);
}

I can use this function "inline" anywhere I want and it should also be "static" because it's not associated with any object, like an Objective-c method. What is the point / advantage of specifying "static" and "inline"?

like image 868
iamjustaprogrammer Avatar asked Feb 17 '14 17:02

iamjustaprogrammer


People also ask

Why should inline function be static?

A static local variable in an extern inline function always refers to the same object. A string literal in the body of an extern inline function is the same object in different translation units*". A function marked static has no external linkage, so inverse applies.

What is the use of static inline function in C?

Static inline functions are simple. Either a function defined with the inline function specifier is inlined at a reference, or a call is made to the actual function. The compiler can choose which to do at each reference. The compiler decides if it is profitable to inline at -xO3 and above.

Does static inline improve performance?

The main reason is performance: when used appropriately, inline functions could enable the compiler to generate more efficient code. A good strategy for identifying performance bottlenecks is to profile the code. Once that's done, the most effective way to improve performance is by focusing on the bottlenecks.


4 Answers

inline does not mean you can use the function “inline” (it is normal to use functions inside other functions; you do not need inline for that); it encourages the compiler to build the function into the code where it is used (generally with the goal of improving execution speed).

static means the function name is not externally linked. If the function were not declared static, the compiler is required to make it externally visible, so that it can be linked with other object modules. To do this, the compiler must include a separate non-inline instance of the function. By declaring the function static, you are permitting all instances of it to be inlined in the current module, possibly leaving no separate instance.

static inline is usually used with small functions that are better done in the calling routine than by using a call mechanism, simply because they are so short and fast that actually doing them is better than calling a separate copy. E.g.:

static inline double square(double x) { return x*x; } 
like image 113
Eric Postpischil Avatar answered Oct 03 '22 19:10

Eric Postpischil


If the storage class is extern, the identifier has external linkage and the inline definition also provides the external definition. If the storage class is static, the identifier has internal linkage and the inline definition is invisible in other translation units.

By declaring a function inline, you can direct the compiler to integrate that function's code into the code for its callers (to replace the complete code of that function directly into the place from where it was called). This makes execution faster by eliminating the function-call overhead. That's why inline functions should be very short.

like image 44
Merlevede Avatar answered Oct 03 '22 19:10

Merlevede


In C, inline means that it is an inline definition. It doesn't have internal linkage, it has no linkage. It never reaches the linker, which means that if the compiler doesn't use that inline definition to inline every single reference to the function in the compilation unit, then there will be a local linker error if a symbol with the same name (C uses unmangled identifiers) with external linkage is not exported by another translation unit in the compilation. The actual inlining of references to the function by the compiler is exclusively controlled by the optimisation flag or __attribute__((always_inline))

There is no difference between static inline and static, both do not inline the function, and provide the function in the assembly output on -O0 as an internal linkage symbol to the linker, and both inline and optimise out the inclusion of the function in the assembly output on -O1. static inline does have one quirk in that you can use a non-static inline prototype before it, except this prototype is ignored and isn't used as a forward declaration (but using a non-static prototype before a static function is an error).

  • inline (GCC <5.0, which used -std=gnu90 / gnu89 as default) / extern inline (GCC 5.0 onwards, which uses -std=gnu11): This is a compiler only inline definition. Externally visible function emittance (in the assembly output for use of the assembler and linker) for this inline definition does not occur. If all references to the function in the file are not actually inlined by the compiler (and inlining occurs on higher optimisation levels or if you use __attribute__((always_inline)) inline float func()), then there will be a local linker error if the compiler does not emit the external definition to the linker (and if a symbol with the same name with external linkage is not exported by another translation unit). This allows for an inline definition and an out-of-line function of the same symbol to be defined separately, one with inline and the other out-of-line, but not in the same translation unit as the compiler will confuse them, and an out of line definitition will be treated as a redefinition error. Inline definitions are only ever visible to the compiler and each translation unit can have their own. Inline definitions cannot be exported to other files because inline definitions do not reach the linking stage. In order to achieve this at compile-time, the inline definition can be in a header file and included in each translation unit. This means that the use of inline is a compiler directive and extern/static refer to the out-of-line version produced for the linker. If the function is not defined in the translation unit, it cannot be inlined because it's left to the linker. If the function is defined but not inline, then the compiler will use this version if it decides to inline

  • extern inline (GCC <5.0) / inline (GCC >5.0): an externally visible function is emitted for this inline definition regardless of whether it is inlined or not meaning this specifier can only be used in one of the translation units. This is intuitively the opposite of 'extern'

  • static inline: locally visible out-of-line function is emitted by the compiler to the assembly output with a local directive for the assembler for this compiler inline definition, but may be optimised out on higher optimisation levels if all the functions are able to be inlined; it will never allow a linker error to result. It behaves identically to static because the compiler will inline the static definition on higher optimisation levels just like static inline.

  • An inline function that isn't static shouldn't contain non-const static storage duration variables or access static file-scope variables, this will produce a compiler warning. This is because the inline and out-of-line versions of the function will have distinct static variables if the out-of-line version is provided from a different translation unit. The compiler may inline some functions, not emit a local symbol to be linked to those references, and leave the linkage to the linker which might find an external function symbol, which is assumed to be the same function as it has the same identifier. So it reminds the programmer that it should logically be const because modifying and reading the static will result in undefined behaviour; if the compiler inlines this function reference, it will read a fresh static value in the function rather than the one written to in a previous call to the function, where that previous reference to the function was one that wasn't inlined, hence the variable that was written to in the previous call would have been one provided by a different translation unit. In this instance, it results in a copy local to each translation unit and a global copy and it is undefined as to which copy is being accessed. Making it const ensures that all the copies are identical and will never change with respect to each other, making the behaviour defined and known.

  • Using an inline / extern inline prototype before/after a non-inline definition means that the prototype is ignored.

  • Using an inline prototype before an inline definition is how to prototype an inline function without side effects, declaring an inline prototype after the inline definition changes nothing unless the storage specifier changes.

  • Using an extern inline / extern / regular prototype before/after an inline definition is identical to an extern inline definition; it is a hint that provides an external out-of-line definition of the function, using the inline definition.

  • Using extern inline / inline on a prototype without a definition in the file but it is referenced in the file results in inline being ignored an then it behaves as a regular prototype (extern / regular, which are identical)

  • Using a static inline / static on a prototype without a definition in the file but it is referenced in the file results in correct linkage and correct type usage but a compiler warning saying that the function with internal linkage has not been defined (so it uses an external definition)

  • Using a regular / extern / extern inline prototype before a static inline or static definition is a 'static declaration of 'func' follows non-static declaration' error; using it after does nothing and they are ignored. Using a static or static inline prototype before/after a static inline definition is allowed. Using an inline prototype before a static inline definition is ignored and will not act as a forward declaration. This is the only way in which static inline differs from static as a regular prototype before a static definition results in an error, but this does not.

  • Using a static inline prototype before a regular / extern / static / static inline / extern inline definition results in static inline overriding the specifiers and acts as correctly as a forward declaration.

  • __attribute__((always_inline)) always inlines the function symbol in the translation unit, and uses this definition. The attribute can only be used on definitions. The storage / inline specifiers are unaffected by this and can be used with it.

like image 42
Lewis Kelsey Avatar answered Oct 03 '22 19:10

Lewis Kelsey


Inline functions are for defining in header files.Small functions are defined in header files. It should be static so that it can acess only static members.

like image 22
Mayank Agarwal Avatar answered Oct 03 '22 19:10

Mayank Agarwal