27

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"?

iamjustaprogrammer
  • 1,634
  • 2
  • 17
  • 34
  • This post might answer your question http://stackoverflow.com/questions/145838/benefits-of-inline-functions-in-c – user376507 Feb 17 '14 at 17:38
  • take a look at this answer (to a slightly different question) http://stackoverflow.com/a/7767858/464988 – MByD Feb 17 '14 at 17:40

4 Answers4

61

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; }
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    I'd upvote if you mentioned the actual use case in this instance - a simple function that's likely called repeatedly. – Joe Feb 17 '14 at 17:46
  • "inline" is clear to me, but "static" still doesn't make sense. What do you mean by "externally visible"? And what do you mean by "module"? I still have to import header files containing static and non-static functions. What's the difference in grandmother terms? – iamjustaprogrammer Feb 17 '14 at 17:54
  • 1
    @iamjustaprogrammer: In a simplified nutshell, if it's *not* static, you can define a function in one `.m` file and call it from another. If it *is* static, you can't do that, you can only call it from the `.m` file in which you define it. If you define it in an `.h` file, then obviously it will be defined in every `.m` file in which you included that header. – Crowman Feb 17 '14 at 18:00
  • 6
    A **module** is one compilation unit: one source file plus all the header files it includes. When you compile several modules separately, they must be linked together into a program. The way `static` is used comes partly from the history of the language. If we were redefining it from scratch today, we might call this use of it `internal` instead. The concept involved is called **linkage**. Identifiers in C can have three type of linkage: external, internal, and none. An identifier with external linkage can be used in multiple modules, and, because they are linked, the identifier will refer… – Eric Postpischil Feb 17 '14 at 18:03
  • 5
    … to the same object in different modules. An identifier with internal linkage refers to an object only within one module. If you use the same identifier in a different module, it refers to a different object; they are not linked to refer to the same object. (By the way, what I call a module here is what the C standard refers to as a **translation unit**.) An identifier with internal linkage can be used in multiple functions inside one module to refer to the same object. Then there are identifiers with no linkage. They refer to an object only within the block in which they are declared. – Eric Postpischil Feb 17 '14 at 18:05
  • 5
    The rules for what linkage identifiers have is a bit complicated due to history. Roughly, identifiers declared at file scope have external linkage by default. Adding `static` changes them to internal linkage. Identifiers declared at block scope (inside functions) have no linkage by default. Adding `static` also changes them to internal linkage. Here is a complication: Adding `extern` instead changes a declaration at block scope to refer to a previously visible declaration instead of having no linkage. That previously visible declaration could have `static`, resulting in… – Eric Postpischil Feb 17 '14 at 18:07
  • 4
    … a declaration marked `extern` referring to an identifier with internal linkage. On top of that, `static` not only changes the linkage of identifiers declared in blocks, it changes the storage class of their objects (when the objects are created and destroyed). – Eric Postpischil Feb 17 '14 at 18:09
  • 3
    Correction: Identifiers declared with `static` at block scope still have no linkage, not internal linkage. Only at file scope does `static` impart internal linkage. – Eric Postpischil Feb 17 '14 at 18:56
  • 1
    You should include all these details in your answer for the benefit of the reader :) – ajay Feb 17 '14 at 19:44
  • @ajay: Since they are different topics, I would prefer to provide links to good answers for the specific issues involved. But I have not taken the time to hunt them down. – Eric Postpischil Feb 17 '14 at 19:46
  • 2
    Doesn't `inline` imply internal linkage in C (as opposed to C++), if external linkage is not explicitly requested? 6.7.4p7 says something like "An inline definition does not provide an external definition for the function" but I'm not sure if I understand that correctly. – dyp Aug 26 '16 at 13:43
  • @dyp it 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. 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 – Lewis Kelsey Feb 15 '21 at 10:48
  • 1
    `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). The actual inlining of references to the function by the compiler is exclusively controlled by the optimisation flag or `__attribute__((always_inline))` – Lewis Kelsey Feb 15 '21 at 10:51
3

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.

Merlevede
  • 8,140
  • 1
  • 24
  • 39
  • 3
    I'm a bit rusty on my Obj-C, but I thought that a C static didn't have much to do with Obj-C classes and static (class) methods, especially as this is a function not a method? – Joe Feb 17 '14 at 17:40
3

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.

Lewis Kelsey
  • 4,129
  • 1
  • 32
  • 42
1

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.

Mayank Agarwal
  • 447
  • 1
  • 7
  • 21