183

What is the point of making a function static in C?

sarnold
  • 102,305
  • 22
  • 181
  • 238
Cenoc
  • 11,172
  • 21
  • 58
  • 92
  • 8
    @nightcracker: There are no such things as "methods" in C++. I think you're confused with Objective-C. – Bo Persson Mar 16 '11 at 16:17
  • 1
    Nah, I'm confused with Python. A function inside a class is called a method in Python. – orlp Mar 16 '11 at 16:25
  • 7
    possible duplicate of [What is a "static" function? (in C)](http://stackoverflow.com/questions/558122/what-is-a-static-function-in-c) – atoMerz Mar 07 '14 at 11:53

7 Answers7

225

Making a function static hides it from other translation units, which helps provide encapsulation.

helper_file.c

int f1(int);        /* prototype */
static int f2(int); /* prototype */

int f1(int foo) {
    return f2(foo); /* ok, f2 is in the same translation unit */
                    /* (basically same .c file) as f1         */
}

int f2(int foo) {
    return 42 + foo;
}

main.c:

int f1(int); /* prototype */
int f2(int); /* prototype */

int main(void) {
    f1(10); /* ok, f1 is visible to the linker */
    f2(12); /* nope, f2 is not visible to the linker */
    return 0;
}
mwfearnley
  • 3,303
  • 2
  • 34
  • 35
pmg
  • 106,608
  • 13
  • 126
  • 198
  • 10
    Is translation unit the correct terminology to use here? Wouldn't object file be more accurate? From what I understand, a static function is hidden from the linker and the linker does not operate on translation units. – Steven Eckhoff Feb 13 '14 at 18:32
  • 3
    I should have also said, that I like to think of it as being hidden from the linker; it seems clearer that way. – Steven Eckhoff Feb 13 '14 at 18:51
  • 1
    so, internal function (that we sure not to call it outside of its c file), we should put it as static function, right ? So, we can sure it cannot call elsewhere. Thanks :) – hqt Jul 06 '14 at 03:30
  • 2
    How do you compile this? Do you use `#include `? I think that would make it a single translation unit then... – Atcold Aug 23 '16 at 01:30
  • 2
    @Atcold: the way I wrote the code you simply include the 2 source files in the command line, like this `gcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c`. The prototypes for the functions are present in both source files (no need for header files). The linker will resolve the functions. – pmg Aug 23 '16 at 08:37
  • 1
    When the goal is to make a function "private" to the current file, another way of doing this is to not put the prototype in the header file and to only include the header file (not the .c file) in other files. That is, only declare the function in a separate compilation unit. When this is done, it seems like there's no need to declare the function `static`. The latter practice actually seems more common in the wild. Please explain if I'm wrong, I'm a little foggy on this, even though it's basic. – Max Heiber Jan 03 '17 at 02:30
  • 1
    @mheiber: when you don't declare a function `static` the linker can find it even without a prototype. The absence of the prototype prevents the compiler from checking return and parameter types, not from issuing code that calls the function. – pmg Jan 03 '17 at 09:50
  • @pmg thanks for explaining. I couldn't actual test the behavior you describe, since my code wouldn't compile when I tried to call something that wasn't in the header file. Also, when I look at C projects on GitHub, I'm just not seeing "private" functions (functions one wouldn't want called outside the current file) declared static—are these developers doing things incorrectly? (sorry for all the noob questions!) – Max Heiber Jan 03 '17 at 22:54
  • How does it help provide encapsulation? Didn't you mean data hiding? – handris May 18 '17 at 08:49
  • @handris static implies internal linkage, hence its inaccessible in other `.c` files(translation units) – Kunal Mukherjee Oct 02 '20 at 14:50
  • Your answer is correct but the file organisation is inappropriate. You should create a header `helper_file.h`, **declare** functions in the `helper_file.h` and define them in `helper_file.c`. Then the `main.c` file should **include** the `helper_file.h`. See my answer below. – mercury0114 Oct 08 '20 at 20:21
85

pmg is spot on about encapsulation; beyond hiding the function from other translation units (or rather, because of it), making functions static can also confer performance benefits in the presence of compiler optimizations.

Because a static function cannot be called from anywhere outside of the current translation unit (unless the code takes a pointer to its address), the compiler controls all the call points into it.

This means that it is free to use a non-standard ABI, inline it entirely, or perform any number of other optimizations that might not be possible for a function with external linkage.

mwfearnley
  • 3,303
  • 2
  • 34
  • 35
Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
  • 12
    ...unless the function's address is taken. – caf Mar 16 '11 at 00:06
  • 1
    @caf What do you mean by function's address is taken? To me, the notion of functions/variable having addresses or being assigned address at compile time is a little confusing. Can you please elaborate? – SayeedHussain Aug 02 '13 at 12:43
  • 3
    @crypticcoder: Your program is loaded in memory, therefore functions also have a memory location and the address can be obtained. With a function pointer, you could call any of those. If you do that, it reduces the list of optimizations the compiler can perform since the code must stay intact at the same place. –  Aug 02 '13 at 17:23
  • 6
    @crypticcoder: I mean that an expression evaluates a pointer to the function and does something with it other than immediately call the function. If a pointer to a `static` function escapes the current translation unit, then that function could be directly called from other translation units. – caf Aug 03 '13 at 00:02
  • 1
    @caf if the function's address is taken, would the compiler detect that and turn off the static function optimizations mentioned in this answer (eg using a non-standard ABI)? I suppose it'd have to. – sevko Jul 12 '18 at 15:52
  • 1
    @sevko: Yes - it's not too hard though, because being static at least any expression that takes the function's address has to be in the same source file. – caf Jul 13 '18 at 00:01
33

The static keyword in C is used in a compiled file (.c as opposed to .h) so that the function exists only in that file.

Normally, when you create a function, the compiler generates cruft the linker can use to, well, link a function call to that function. If you use the static keyword, other functions within the same file can call this function (because it can be done without resorting to the linker), while the linker has no information letting other files access the function.

3Doubloons
  • 2,088
  • 14
  • 26
  • 2
    3Doub: Use of the word "cruft" is more precise than you give it credit for. In the context of the question, "cruft" is the right word to use here. – Erik Aronesty Nov 20 '14 at 21:16
  • 1
    @3Doubloons I agree that it's simplified, but I think that makes it that much easier to understand for beginners. – Ingo Bürk Mar 25 '15 at 07:47
14

Looking at the posts above I would like to give a more clarified answer:

Suppose our main.c file looks like this:

#include "header.h"

int main(void) {
    FunctionInHeader();
}

Now consider three cases:

  • Case 1: Our header.h file looks like this:

     #include <stdio.h>
    
     static void FunctionInHeader();
    
     void FunctionInHeader() {
         printf("Calling function inside header\n");
     }
    

    Then the following command on linux:

     gcc main.c -o main
    

    will succeed! That's because after the main.c file includes the header.h, the static function definition will be in the same main.c file (more precisely, in the same translation unit) to where it's called.

    If one runs ./main, the output will be Calling function inside header, which is what that static function should print.

  • Case 2: Our header header.h looks like this:

      static void FunctionInHeader();     
    

    and we also have one more file header.c, which looks like this:

      #include <stdio.h>
      #include "header.h"
    
      void FunctionInHeader() {
          printf("Calling function inside header\n");
      }
    

    Then the following command

      gcc main.c header.c -o main
    

    will give an error. In this case main.c includes only the declaration of the static function, but the definition is left in another translation unit and the static keyword prevents the code defining a function to be linked

  • Case 3:

    Similar to case 2, except that now our header header.h file is:

      void FunctionInHeader(); // keyword static removed
    

    Then the same command as in case 2 will succeed, and further executing ./main will give the expected result. Here the FunctionInHeader definition is in another translation unit, but the code defining it can be linked.

Thus, to conclude:

static keyword prevents the code defining a function to be linked,
when that function is defined in another translation unit than where it is called.
mercury0114
  • 1,341
  • 2
  • 15
  • 29
5

C programmers use the static attribute to hide variable and function declarations inside modules, much as you would use public and private declarations in Java and C++. C source files play the role of modules. Any global variable or function declared with the static attribute is private to that module. Similarly, any global variable or function declared without the static attribute is public and can be accessed by any other module. It is good programming practice to protect your variables and functions with the static attribute wherever possible.

5

pmg's answer is very convincing. If you would like to know how static declarations work at object level then this below info could be interesting to you. I reused the same program written by pmg and compiler it into a .so(shared object) file

Following contents are after dumping the .so file into something human readable

0000000000000675 f1: address of f1 function

000000000000068c f2: address of f2(staticc) function

note the difference in the function address , it means something . For a function that's declared with different address , it can very well signify that f2 lives very far away or in a different segment of the object file.

Linkers use something called PLT(Procedure linkage table) and GOT(Global offsets table) to understand symbols that they have access to link to .

For now think that GOT and PLT magically bind all the addresses and a dynamic section holds information of all these functions that are visible by linker.

After dumping the dynamic section of the .so file we get a bunch of entries but only interested in f1 and f2 function.

The dynamic section holds entry only for f1 function at address 0000000000000675 and not for f2 !

Num: Value Size Type Bind Vis Ndx Name

 9: 0000000000000675    23 FUNC    GLOBAL DEFAULT   11 f1

And thats it !. From this its clear that the linker will be unsuccessful in finding the f2 function since its not in the dynamic section of the .so file.

human.js
  • 1,342
  • 13
  • 15
0

When there is a need to restrict access to some functions, we'll use the static keyword while defining and declaring a function.

            /* file ab.c */ 
static void function1(void) 
{ 
  puts("function1 called"); 
} 
And store the following code in another file ab1.c

/* file ab1.c  */ 
int main(void) 
{ 
 function1();  
  getchar(); 
  return 0;   
} 
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */