Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static and extern inline functions in C [duplicate]

Tags:

c

I am trying to learn the difference between static and extern functions in detail.

I know the basic difference between static and extern inline functions.

Please correct my understanding if it is wrong:

  • static inline functions are visible only to translation unit where it is defined.
  • extern inline functions can be access in more than one translation units.
  • Better to define inline functions in header files
  • There is no difference between static and static inline function definitions.

Below is a sample code where I got stuck about the behaviour.

file1.c

#include <stdio.h>
#include "file.h"

int main(void)
{
  fun1(); 
  return 0;  
}

static inline void fun1(void)
{
  int i;
  for (i = 0; i < 10; i++) {
      static int k = 20;
      printf("Value : %d \n", k++);
  }
}

file2.c

#include <stdio.h>

inline void fun1(void)
{
  int i;
  int k = 0;
  for (i = 0; i < 10; i++) {
      printf("Value : %d \n", k++);
  }
}

file.h

#ifndef FILE_H
#define FILE_H 

extern inline void fun1(void);

#endif

When I compile the above code "gcc file1.c file2.c", fun1 was called from file2.c. This is clear as it fun1 is declared as extern, it should take the extern function in file2.c( all inline functions are extern by default?).

But when I change the static inline function to static function(static void fun1(void)) in file1.c, fun1 was called from file1.c. What could be the reason ?

I also read like "If an inline function is declared with external linkage but not defined in the same translation unit, the behavior is undefined ". But I didnt understand this. Is this possible to explain with above example?

Is there any difference between static and extern functions in C++ when compared to C ?

like image 504
Salim Avatar asked Jan 09 '18 16:01

Salim


1 Answers

Your code is incorrect because you cannot declare a function with extern (which is default) and afterwards provide a static definition. The fact that it compiles at all does not indicate anything useful.

From n1548 §6.2.2:

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

So, you get something like this in file1.c:

// Has external linkage (which is the default!)
extern inline void fun1(void);

// This would also have external linkage.
inline void fun1(void);

// This has static linkage.
static inline void fun1(void) {
    ...
}

(Note: "external linkage" is the default but extern inline actually means something special, it's different from inline.)

Bam! Undefined behavior. The compiler may not even give you an error message, although some compilers appear to give error messages for this.

error: static declaration of 'func' follows non-static declaration

This error actually has nothing to do with the fact that the function is inline. It is an error with or without inline.

What about those questions?

static inline functions are visible only to translation unit where it is defined.

This is true of all static functions. They have "internal linkage" so you can have static void func(void); in one file and a completely different static int func(char *p); in a different file. The inline makes no difference here.

extern inline functions can be access in more than one translation units.

Yes, which is why you shouldn't put them in header files. If you put them in header files, you will get multiple different definitions of the same function, which can all be accessed from different translation units. This is an error. Instead, put the extern inline in source files, but it only needs to be a declaration, not a definition.

Better to define inline functions in header files

There is no real point to defining an inline function anywhere else. If your function is only used in one file just mark it static and the compiler will decide how to call the function.

There is no difference between static and static inline function definitions.

Yes, there is no difference.

Well, technically, no, there is a difference because the compiler is allowed to treat static inline functions differently from just static functions. However, modern compilers tend to decide to inline functions using their own set of rules, and whether a function is inline doesn't affect that process very much.

Well, practically there is one other difference. A static inline function definition won't generate a warning in GCC if it's not used, but a static function will. This is so you can put a static inline function in a header file. This is an alternative to putting inline in the header file, which requires you to have an extern inline for that function somewhere in your program. However, if the compiler decides that it would rather not inline your static inline function, either because it think's that inlining is worse or because inlining is impossible, then it will have to make a separate copy of that function in each file it's used in.

So, how do you do it correctly?

Never declare a function static if it has a previous, non-static declaration. This is an error, even if it compiles.

Don't declare an inline extern function in a header file. This creates an "external definition" for the function, and you can only have one of those in your entire program.

Don't declare inline functions in header files without defining them. There is no point.

Here is how you would want to do this:

In mylib.h:

// Provide "inline definition" of the function.
inline int times_two(int x) {
    return x * 2;
}

In mylib.c:

#include "mylib.h"

// Provide "external definition" of the function.
extern inline int times_two(int x);

This is the standard way to do things since C99. The compiler should be free to use the internal definition or the external definition, whichever one it thinks is better. If you don't have an external definition or you have more than one, you may get a linking error, just like with regular functions.

C++ has its own completely different rules for inline functions.

like image 78
Dietrich Epp Avatar answered Oct 21 '22 03:10

Dietrich Epp