3

What's the difference between the following scenarios?

// some_file.c
#include "some_file.h" // doesn't declare some_func

int some_func(int i) {
    return i * 5;
}
// ...

and

// some_file.c
#include "some_file.h" // doesn't declare some_func

static int some_func(int i) {
    return i * 5;
}
// ...

If all static does to functions is restrict their accessibility to their file, then don't both scenarios mean some_func(int i) can only be accessed from some_file.c since in neither scenario is some_func(int i) put in a header file?

atirit
  • 1,492
  • 5
  • 18
  • 30
  • 4
    In the first example, even if you don't declare `some_func` in `some_file.h`, it is still accessible by other files using `extern int some_func(int);` (`extern` is optional), in the second one `some_func` is not accessible. – David Ranieri May 08 '20 at 06:06

3 Answers3

4

A static function is "local" to the .c file where it is declared in. So you can have another function (static or nor) in another .c file without having a name collision.

If you have a non static function in a .c file that is not declared in any header file, you cannot call this function from another .c file, but you also cannot have another function with the same name in another .c file because this would cause a name collision.

Conclusion: all purely local functions (functions that are only used inside a .c function such as local helper functions) should be declared static in order to prevent the pollution of the name space.

Example of correct usage:

file1.c

static void LocalHelper()
{
}
...

file2.c

static void LocalHelper()
{
}
...

Example of semi correct usage

file1.c

static LocalHelper()   // function is local to file1.c
{
}
...

file2.c

void LocalHelper()     // global functio
{
}
...

file3.c

void Foo()
{
   LocalHelper();    // will call LocalHelper from file2.c
}
...

In this case the program will link correctly, even if LocalHelpershould have been static in file2.c

Example of incorrect usage

file1.c

LocalHelper()          // global function
{
}
...

file2.c

void LocalHelper()     // global function
{
}
...

file3.c

void Foo()
{
   LocalHelper();       // which LocalHelper should be called?
}
...

In this last case we hava a nema collition and the program wil not even link.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
3

The difference is that with a non-static function it can still be declared in some other translation unit (header files are irrelevant to this point) and called. A static function is simply not visible from any other translation unit.

It is even legal to declare a function inside another function:

foo.c:
void foo()
{
  void bar();
  bar();
}

bar.c:
void bar()
{ ... }
SoronelHaetir
  • 14,104
  • 1
  • 12
  • 23
2

What's the difference between declaring a function static and not including it in a header?

Read more about the C programming language (e.g. Modern C), the C11 standard n1570. Read also about linkers and loaders.

On POSIX systems, notably Linux, read about dlopen(3), dlsym(3), etc...

Practically speaking:

If you declare a function static it stays invisible to other translation units (concretely your *.c source files, with the way you compile them: you could -at least in principle, even if it is confusing- compile foo.c twice with GCC on Linux: once as gcc -c -O -DOPTION=1 foo.c -o foo1.o and another time with gcc -c -O -DOPTION=2 -DWITHOUT_MAIN foo.c -o foo2.o and in some cases be able to link both foo1.o and foo2.o object files into a single executable foo using gcc foo1.o foo2.o -o foo)

If you don't declare it static, you could (even if it is poor taste) code in some other translation unit something like:

if (x > 2) {
  extern int some_func(int); // extern is here for readability
  return some_func(x);
}

In practice, I have the habit of naming all my C functions (including static ones) with a unique name, and I generally have a naming convention related to them (e.g. naming them with a common prefix, like GTK does). This makes debugging the program (with GDB) easier (since GDB has autocompletion function names).

At last, a good optimizing compiler could, and practically would often, inline calls to static functions whose body is known. With a recent GCC, compile your code with gcc -O2 -Wall. If you want to check how inlining happened, look into the produced assembler (using gcc -O2 -S -fverbose-asm).

On Linux, you can obtain using dlsym the address of a function which is not declared static.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547