99

I have a function that is declared and defined in a header file. This is a problem all by itself. When that function is not inlined, every translation unit that uses that header gets a copy of the function, and when they are linked together there are duplicated. I "fixed" that by making the function inline, but I'm afraid that this is a fragile solution because as far as I know, the compiler doesn't guarantee inlining, even when you specify the "inline" keyword. If this is not true, please correct me.

Anyways, the real question is, what happens to static variables inside this function? How many copies do I end up with?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Dirk Groeneveld
  • 2,547
  • 2
  • 22
  • 23

9 Answers9

125

I guess you're missing something, here.

static function?

Declaring a function static will make it "hidden" in its compilation unit.

A name having namespace scope (3.3.6) has internal linkage if it is the name of

— a variable, function or function template that is explicitly declared static;

3.5/3 - C++14 (n3797)

When a name has internal linkage , the entity it denotes can be referred to by names from other scopes in the same translation unit.

3.5/2 - C++14 (n3797)

If you declare this static function in a header, then all the compilation units including this header will have their own copy of the function.

The thing is, if there are static variables inside that function, each compilation unit including this header will also have their own, personal version.

inline function?

Declaring it inline makes it a candidate for inlining (it does not mean a lot nowadays in C++, as the compiler will inline or not, sometimes ignoring the fact the keyword inline is present or absent):

A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.

7.1.2/2 - C++14 (n3797)

In a header, its has an interesting side effect: The inlined function can be defined multiple times in the same module, and the linker will simply join "them" into one (if they were not inlined for compiler's reason).

For static variables declared inside, the standard specifically says there one, and only one of them:

A static local variable in an extern inline function always refers to the same object.

7.1.2/4 - C++98/C++14 (n3797)

(functions are by default extern, so, unless you specifically mark your function as static, this applies to that function)

This has the advantage of "static" (i.e. it can be defined in a header) without its flaws (it exists at most once if it is not inlined)

static local variable?

Static local variables have no linkage (they can't be referred to by name outside their scope), but has static storage duration (i.e. it is global, but its construction and destruction obey to specific rules).

static + inline?

Mixing inline and static will then have the consequences you described (even if the function is inlined, the static variable inside won't be, and you'll end with as much static variables as you have compilation units including the definition of your static functions).

Answer to author's additional question

Since I wrote the question I tried it out with Visual Studio 2008. I tried to turn on all the options that make VS act in compliance with standards, but it's possible that I missed some. These are the results:

When the function is merely "inline", there is only one copy of the static variable.

When the function is "static inline", there are as many copies as there are translation units.

The real question is now whether things are supposed to be this way, or if this is an idiosyncrasy of the Microsoft C++ compiler.

So I suppose you have something like that:

void doSomething()
{
   static int value ;
}

You must realise that the static variable inside the function, simply put, a global variable hidden to all but the function's scope, meaning that only the function it is declared inside can reach it.

Inlining the function won't change anything:

inline void doSomething()
{
   static int value ;
}

There will be only one hidden global variable. The fact the compiler will try to inline the code won't change the fact there is only one global hidden variable.

Now, if your function is declared static:

static void doSomething()
{
   static int value ;
}

Then it is "private" for each compilation unit, meaning that every CPP file including the header where the static function is declared will have its own private copy of the function, including its own private copy of global hidden variable, thus as much variables as there are compilation units including the header.

Adding "inline" to a "static" function with a "static" variable inside:

inline static void doSomething()
{
   static int value ;
}

has the same result than not adding this "inline" keyword, as far as the static variable inside is concerned.

So the behaviour of VC++ is correct, and you are mistaking the real meaning of "inline" and "static".

paercebal
  • 81,378
  • 38
  • 130
  • 159
  • 1
    I think you are missing an important point to mention, that at the linking phase all those static variables declared in inline function would be resolved to one, am I wrong? – user14416 Feb 25 '16 at 20:51
  • 1
    No, because each static variables is inside its own separate function: Despite the fact the functions have the same name, they have internal linkage, and thus, are not shared accross translation units. – paercebal Feb 26 '16 at 22:05
  • 1
    @paercebal in `inline void doSomething() { static int value ; }`, the function has external linkage ; this is an ODR violation if it appears in a header that's included from two different units – M.M Dec 06 '18 at 22:36
  • @M.M what do you mean? Your function is `inline`, it can't violate ODR. – Ruslan Feb 02 '19 at 19:07
  • @Ruslan that's a non-sequitur – M.M Feb 02 '19 at 20:52
  • What about plain c- inline function containing static variable. I suspect behavior should be the same as c++ one, is it documented anywhere? – uuu777 Jun 20 '20 at 18:32
  • 1
    @zzz777 I am not familiar with C's standard, but in a C201x standard draft (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf), in 6.7.4§3 (Function specifiers), you have: "An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage." which seems to rule out extern inline function with static local variables. I thought extern was the default for functions, but apparently not in this context... I don't know... See also §7... – paercebal Jun 21 '20 at 20:50
  • @paercebal In the mean time I found that it will different static variable in every translation unit. So it is not working like c++. – uuu777 Jun 22 '20 at 00:52
  • @uuu777 In C the semantics of `inline` are subtly/confusingly different. See https://www.ibm.com/docs/en/zos/2.4.0?topic=specifiers-inline-function-specifier ("[In C], Static local variables are not allowed to be defined within the body of an inline function.). In practice it's a warning not an error, but it means different TUs are not required to reference the same var like in C++. – 1110101001 Jan 23 '23 at 02:31
  • (Cont.) In practice I think how that could happen is if it gets inlined into the caller, each inlined version may reference its own version of the static. I don't know why it wasn't decided to require all inlined copies to reference the same like C++ did, but seems as a principle the C approach to `inline` leaves less things for the linker to do (e.g. unlike in C++ where it's the linkers job to resolve duplicate symbols of a func marked inline across TUs, in C if things couldn't be inlined into the caller then there _must_ exist exactly one `extern inline` version in a TU). – 1110101001 Jan 23 '23 at 02:39
45

I believe the compiler creates many copies of the variable, but the linker picks one and makes all the others reference it. I had similar results when I tried an experiment to create different versions of an inline function; if the function wasn't actually inlined (debug mode), all calls went to the same function regardless of the source file they were called from.

Think like a compiler for a moment - how could it be otherwise? Each compilation unit (source file) is independent of the others, and can be compiled separately; each one must therefore create a copy of the variable, thinking it is the only one. The linker has the ability to reach across those boundaries and adjust the references for both variables and functions.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 3
    AFAICT, you're perfectly correct in what you are saying here. I do not understand why people are down voting this answer. My only guess is that they read as far as "many copies of the variable", and then stop! :( Anyway a token (+1) from me. – Richard Corden Oct 09 '08 at 08:25
  • 3
    When people ask about what the compiler does they mean the compiler + the linker, since you can't run object files. So this answer is correct but totally meaningless. – Evan Dark Jan 29 '12 at 18:38
  • 1
    Because people are ignorant.This is more advanced question and all are supposed to make the distinction in the discussion. – Sogartar Apr 05 '12 at 12:47
  • Actually, this answer is perfectly meaningful. It answers the "meant" question, but still uses correct terms. – Alex Che Mar 11 '21 at 15:31
  • I just tested this with gcc v9.3.0 and it DOES include a copy of static variables for each file a function is inlined in even after linked and stripped. So in my case I had 3 source files each using the same inline function. The static data from the inline function showed up 3 times in the compiled binary (compiled with `-s -O2`). clang v10.0.0 did the same thing. – CR. Aug 30 '21 at 02:35
  • @CR. did you check to see how many of those 3 static variables were accessible by the code? My assertion is that even if 3 of them were compiled into the binary file, the code would only use one of them and the other 2 would be wasted space. – Mark Ransom Aug 30 '21 at 04:19
  • @MarkRansom Yes, I checked the pointers. Each version of the inlined function had its own pointer to a distinct set of static data. – CR. Aug 30 '21 at 18:28
  • Clang will even warn if you do this `warning: non-constant static local variable in inline function may be different in different files [-Wstatic-local-in-inline]` – 1110101001 Jan 23 '23 at 00:54
  • You can see http://kyungminlee.org/doc/minutiae/local_static_variable_shared_library.html for more information. IMO all the other answers are misleading because none of them show what actually happens. Behavior in C vs C++ also needs to be distinguished. – 1110101001 Jan 23 '23 at 01:01
  • @1110101001 - question is about C++ not C. In C++ there is only one copy of the static variable in an inline function across TUs. – BeeOnRope Jun 02 '23 at 01:13
12

I found Mark Ransom's answer helpful - that the compiler creates many copies of the static variable, but the linker chooses one and enforces it across all translation units.

Elsewhere I found this:

See [dcl.fct.spec]/4

[..] An inline function with external linkage shall have the same address in all translation units. A static local variable in an extern inline function always refers to the same object. A string literal in an extern inline function is the same object in different translation units.

I don't have a copy of the standard to check, but it matches with my experience examining the assembly in VS Express 2008

YSC
  • 38,212
  • 9
  • 96
  • 149
Matt
  • 121
  • 1
  • 3
6

It is supposed to be this way. "static" tells the compiler you want the function to be local to the compilation unit, therefore you want one copy per compilation unit and one copy of the static variables per instance of the function.

"inline" used to tell the compiler you want the function to be inlined; nowadays, it just takes it as "it's ok if there are several copies of the code, just make sure it's the same function". So everybody shares the static variables.

Note: this answer was written in response to the answer the original poster posted to himself.

Raphaël Saint-Pierre
  • 2,498
  • 1
  • 19
  • 23
  • 2
    He is asking about 'static variables' in an 'inline function', not variables in a static function. – Richard Corden Oct 09 '08 at 08:22
  • We agree on that, but you're right: an edit is needed to put the answer back in context. – Raphaël Saint-Pierre Oct 10 '08 at 18:43
  • I came across [this](https://stackoverflow.com/a/9370717/491827) too. So which of the two is it? `inline` causes the function to be inlined or it's ok to have multiple copies? – Vassilis Dec 31 '18 at 13:57
  • @Vassilis both are right, though `inline` does not *cause* inlining, it just suggests it, and it allows for more than one definition (but not in the same compile unit). – Raphaël Saint-Pierre Jan 02 '19 at 16:37
3

Since I wrote the question I tried it out with Visual Studio 2008. I tried to turn on all the options that make VS act in compliance with standards, but it's possible that I missed some. These are the results:

When the function is merely "inline", there is only one copy of the static variable.

When the function is "static inline", there are as many copies as there are translation units.

The real question is now whether things are supposed to be this way, or if this is an ideosyncracy of the Microsoft C++ compiler.

Dirk Groeneveld
  • 2,547
  • 2
  • 22
  • 23
  • 1
    "When the function is "static inline"," -- Your original posting didn't say anything about doing that. You should expect different results because static on a function has a different meaning from static on a variable. static on a function means other translation units won't see this definition. – Windows programmer Oct 09 '08 at 02:43
  • not sure of your settings but the compiler is working correctly in this case. However you may want to include a unit test, in case you run into some non conforming compiler down the road. – Robert Gould Oct 09 '08 at 02:56
-2

Inlining means that executable code (instructions) is inlined into the calling function's code. The compiler can choose to do that regardless of whether you've asked it to. That has no effect on the variables (data) declared in the function.

Windows programmer
  • 7,871
  • 1
  • 22
  • 23
-3

Static means one copy is distributed throughout the program , but inline means it requires the same code for several time in the same program , so it is not possible to make a variable static inside the inline function.

-4

I believe you will end up with one per translation unit. You've effectively got many versions of that function (and its declared static variable), one for every translation unit that includes the header.

Jason Etheridge
  • 6,849
  • 5
  • 30
  • 33
-4

Besides any design issues this all may imply, since you're already stuck with it, you should use static in this case not inline. That way everyone shares the same variables. (Static function)

Robert Gould
  • 68,773
  • 61
  • 187
  • 272