40

I have a .cpp file which has some static free functions. I know how that would help in a header file, but since the cpp is not included anywhere, what's the point? Are there any advantages to it?

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625

3 Answers3

83

Declaring free functions as static gives them internal linkage, which allows the compiler more aggressive optimizations, as it is now guaranteed that nobody outside the TU can see that function. For example, the function might disappear entirely from the assembly and get inlined everywhere, as there is no need to provide a linkable version.

Note of course that this also changes the semantics slightly, since you are allowed to have different static functions of the same name in different TUs, while having multiple definitions of non-static functions is an error.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thx, a type of answer I was hoping for. – Luchian Grigore Sep 30 '11 at 13:48
  • 5
    "you are allowed to have different static functions of the same name in different TUs" - nameless namespaces can provide that effect too, if you enjoy curly braces and extra indentation ;-) – Steve Jessop Sep 30 '11 at 14:40
  • 1
    @SteveJessop: That's true (and we don't indent for namespaces :-) ), but was that added in C++11? The internal linkage, I mean. – Kerrek SB Nov 01 '13 at 22:01
  • 2
    Yes, the fact that nameless namespaces have internal linkage is new to C++11. – Steve Jessop Nov 02 '13 at 00:02
  • Surely the compiler can do all this anyway? The `inline` keyword is basically ignored in modern compilers - "Clang treats it as a mild suggestion from the programmer.", so it wouldn't change inlining, and the linker can remove functions that aren't used. – Timmmm May 16 '14 at 13:39
10

Since comment boxes are too small to explain why you have a serious error in your reasoning, I'm putting this as a community wiki answer. For header-only functions, static is pretty much useless because anyone who includes their header will get a different function. That means you will duplicate code the compiler creates for each of the functions (unless the linker can merge the code, but by all I know, that's very unlikely), and worse, if the function would have local statics, each of those locals would be different, resulting in potentially multiple initializations for each call to a definition from a different inclusion. Not good.

What you need for header-only functions is inline (non-static inline), which means each header inclusion will define the same function and modern linkers are capable of not duplicating the code of each definition like done for static (for many cases, the C++ Standard even requires them to do so), but emitting only one copy of the code out of all definitions created by all inclusions.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    I think you're exaggerating the extent to which making a function `inline` prevents code duplication. Marking it `inline` doesn't prevent the compiler from actually inlining it, thus duplicating a significant part of the code if not the prolog etc. But it does avoid the likely situation where a large `static` function might be duplicated even in situations where, given free reign, the compiler would choose not to inline it. – Steve Jessop Sep 30 '11 at 14:01
  • @Steve I'm not saying something about about inlining calls to functions. No keyword in Standard C++ can prevent inlining calls to functions, be it to `inline` functions or to `static` functions. It's the compiler's business, and it will inline calls to `static` and `inline` functions as it wishes. – Johannes Schaub - litb Sep 30 '11 at 14:04
  • You said, "modern linkers will not duplicate the code of each definition". Given the existence of inlining, I think that statement was misleading. More accurate perhaps would be, "modern linkers are capable of not duplicating the code". – Steve Jessop Sep 30 '11 at 14:05
  • 1
    @Steve you are right about the misleading factor. However the Standard even requires linkers to not duplicate their code if you take the address of their function and print it / compare it across TUs. And for that reason, afaik, code generated for inline functions are put into specially named sections, so that the linker can easily throw away all but a single copy of the code. For `static` functions, no such thing is done. Why would a compiler choose to say "ah, I *want* code bloat, so I put this inline function into `.text`, so it cannot be merged!"? – Johannes Schaub - litb Sep 30 '11 at 14:12
  • Note that my whole answer is done in the assumption that no call inlining happens. That is because if call inlining *does* happen, then `inline` and `static` both have the same code bloat factor - both will end up with the code of the called function in their TU. But if inlining does *not* happen, `inline` functions have that significant benefit. – Johannes Schaub - litb Sep 30 '11 at 14:17
  • OK, so assuming no inlining occurs then I don't think anything here is misleading. For a function that you strongly expect to be inlined, and whose address you don't take, marking it `static` could mean that the "full function" is emitted 0 times, which is even better than 1. But of course for the function to be very likely to inline, it has to be fairly small, so arguably you wouldn't care whether it's emitted or not. – Steve Jessop Sep 30 '11 at 14:26
  • @Steve the inline function will then be emitted `0` times too, because it is useless - an `inline` function must be defined in the same TU where it is called, and if a function is declared `inline` in one TU, it must be declared so in any other TU. So any TU wanting to call the function cannot rely on an emitted version of it from another TU, so the compiler can safely emit it 0 times if it is not called at all. – Johannes Schaub - litb Sep 30 '11 at 14:28
  • Recommended question: http://stackoverflow.com/questions/3647053/what-is-are-the-purposes-of-inline – Johannes Schaub - litb Sep 30 '11 at 14:30
  • So what that amounts to is that `inline` functions in effect have internal linkage, in the sense that they cannot be used in any way that requires them to behave as if they have external linkage? Of course the linker has to see them to merge the definitions, but as far as the program is concerned, `static inline` only differs from `inline` in those odd corner cases where the function uses some other object or function with internal linkage, and hence is an ODR violation if it's not `static`? – Steve Jessop Sep 30 '11 at 14:33
  • 1
    @Steve not at all :) A `static inline` has different addresses in different TUs (because the definitions have internal linkage and hence define different functions), a non-static `inline` has same addresses in different TUs (because the definitions have external linkage and hence define the same function). And if they have a local static variable you get multiple objects in the first case, and only one object and initialization of that object in the second case. – Johannes Schaub - litb Sep 30 '11 at 14:40
  • OK: `inline` functions whose address you don't take. I was thinking of these situations where either a `static` or an `inline` function can be emitted 0 times, but I didn't say so. I guess SO is right, and this discussion has gone on too long for comments, since I'm forgetting which specific case I'm in. – Steve Jessop Sep 30 '11 at 14:45
0

A bit out of order response because the first item addressed raises some huge questions in my head.

but since the cpp is not included anywhere

I strongly hope that you never #include a source file anywhere. The preprocessor doesn't care about the distinction between source versus header. This is distinction exists largely to benefit humans, not the compilers. There are many reasons you should never #include a source file anywhere.

I have a .cpp file which has some static free functions. I know how that would help in a header file ...

How would that help?

You declare non-static free functions in a header if those free functions have external linkage. Declaring (but not defining) static free functions in a header doesn't help. It is a hindrance. You want to put stuff in a header that helps you and other programmers understand the exported content of something. Those static free functions are not exported content. You can define free functions in a header and thus make them exported content, but the standard practice is to use the inline keyword rather than static.

As far as your static free functions in your source file, you might want to consider putting the declarations of those functions near the top of the source file (but not in a header). This can help improve understandability. Without those declarations, the organization of the source file will look Pascalish, with the low-level functions defined first. Most people like a top-down presentation. By declaring the functions first you can employ a top-down strategy. Or an inside out strategy, or whatever strategy makes the functionality easiest to understand.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • "Most people like a top-down presentation". I disagree, but that's only my personal opinion. Do you have actual statistics to prove this statement? – DeltA Nov 16 '22 at 06:08