8

Although this question has come up before, mine is different because it is not supposed to cover anything OOP but only plain (ANSI) C.

Especially in open-source software, I usually encounter a plethora of functions (please don't call them methods since we're not in OOP) with the static keyword preceding the data type.

But what effect does this actually have with plain C? In my own projects, I've never had an occasion where the static keyword was actually needed. (Although a so-called expert programmer would probably have given me the advice, "This function should be declared static" and I would probably have replied in my own sarcastic way: "Uh-huh. Well, it works as-is, after all". :)).

From reading the OSS code, I assumed it might just generate less overhead when compiling the project. However, CPU have advanced in performance so much that I've wondered many times why there is such an ongoing interest to declare functions static even though it might need some benchmark tool to measure the differences in execution speed.

1

4 Answers 4

21

"Static" is overloaded to mean two things in C:

  • At the file level, it restricts scope to the current file. (I think this is what you're seeing.)

  • Within a function, it transforms variables such that their values are preserved between calls.

"Static" has little to do with performance in C. In the context in which you saw it used, it relates to scope-of-access. In this usage, "static" actually ends up being similar in function to access modifiers in an OOP language than with the "static" keyword as it applies to C++ methods.

8
  • OK, but can you address the question that the OP asked? Jul 16, 2014 at 18:08
  • 8
    I did. The answer is that "static" has nothing to do with performance in C. It relates to scope-of-access. It actually ends up being similar in function to access modifiers in an OOP language than with the "static" keyword as it applies to C++ methods. And I thought your answer was pretty irrelevant, but I couldn't downvote or comment because I'm not in the "cool kids" club here. Jul 16, 2014 at 18:13
  • Note that in certain historical scenarios (I'm thinking early days of the PC with segment registers, and all that they imply), making the function static to a file might allow the compiler to use a nearer form of jump to get to, therefore shaving a byte or two, and perhaps a cycle or two on calls to the function. Jul 16, 2014 at 22:44
  • 1
    The term isn't "overloaded" as you say—it has the same meaning in both contexts: declaring a global identifier and restricting access. In the case of a global variable/function declared outside a function, it restricts access to within that file; and in the case of a variable declared within a function, it creates a global variable and restricts access to within that function.
    – DaoWen
    Jul 17, 2014 at 1:54
  • FWIW, "overloaded" sounds pretty much like borrowed from OOP lingo to me again. Overloading means to have two or more methods (here no longer: "functions") with same name but two or more different numbers of parameters. "Overloaded" in plain (modular) C sounds somewhat odd (but maybe that's just me). Jul 17, 2014 at 15:34
6

Static, when applied to a function, means that the function has local scope or file scope, which will disallow someone from declaring a prototype to that function in a header file and using it somewhere else than where it was declared.

This has no performance implications, but is a good practice nevertheless. Why? Because it reduces scope. When the programmer spots a static function, it is an indication that the function will not be used in some other unknown place, thus, if you break that function, at least you know the damage should be confined to the source file in question.

Note though that static is not a hard guarantee that the function can't be called outside the file where is was declared, since someone can still grab a pointer to the function and externalize that pointer.

4

Every function or variable in a C program which is not declared static is required to have a unique name. If two or more programmers writing different parts of a system each write a function called "fred", and both functions are declared static, then the fact that there are two "fred" functions will be completely irrelevant (and thus not pose a problem). If all but one of the functions is static, things are still likely to be okay, but there could still be possible problems if a programmer adds an extern declaration somewhere intending it to refer to one function, but the intended function is static and the declaration actually binds to a non-static function declared elsewhere. If there are two or more "fred" functions which aren't static, problems are almost guaranteed. In most cases, the linker will reject the program; in some cases (e.g. if one of the method is tagged with a "weak" attribute) the linker won't squawk, but code which is supposed was intended to invoke one method might invoke the other. If both methods happen to behave identically, that might not pose a problem, but if the methods are different, such substitution is likely to be disastrous.

If programmers default to making their methods non-static, name collisions are likely. Making things static by default avoids that problem.

3

When applied to a function definition, the static keyword prevents the function name from being exported to the linker; code in other translation units (files) cannot call that function by name.

To abuse some terminology, you're making the function definition "private" to that source file.

For example, assume I have a file like

static int a_helper_function( /* some arguments here */ )
{
  ...
}

int public_function( /* some arguments here */ )
{
  ...
  if ( a_helper_function( /* arguments */ ))
    /* do something interesting */
  ...
}

When I build my project, only functions defined within that same source file can call a_helper_function directly; it's not visible to code in other translation units.

This isn't a performance issue so much as a maintenance and design issue. It reduces namespace collisions (you could have multiple versions of a_helper_function with different signatures in different files), and it allows you to encapsulate some operations within each file.

Now, all this does is prevent the function name from being exported to the linker; other translation units can still call this function, just not by name. I could have another function in that same file that returns a pointer to a_helper_function:

int (*get_helper(/* args for get_helper */))(/* args for a_helper_function */)
{
  return a_helper_function;
}

The get_helper function returns a pointer to a_helper_function, so a function in another translation unit could use that function pointer to call a_helper_function.

1
  • THIS might be the actual reason why especially those GNU folks would use static so exorbitantly: to keep certain selected stuff out of the linker's reach. Thank you for your insights, there was lots of valuable information contained within. Jul 22, 2014 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.