Static Variables in an Inlined Function

static variables in an inlined function

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".

exposing static variable through an inline function

Your code is illegal (in both ISO C and GNU C): the body of a function declared as inline must appear in the same translation unit as any call to that function. But in your code it does not appear in app.c, which is why you get the undefined reference error.

Further, as mentioned in comments, in ISO C an inline function that is not also static, may not mention an array with internal linkage. (I don't know what GNU C's rules are in this area).

In comments you talk about stuff like "overhead of CALL" etc. But this has little or nothing to do with the inline keyword. The optimizer will produce the fastest possible code if you use an optimization switch. The purpose of the inline keyword is to allow function bodies to appear in header files.

One option would be to unmark the function as inline, and use the -O2 -flto switches with gcc.

Another option is to use the inline function but put the function body in the header file. In this case you will also need to use extern int data_array[]; etc, because it is not possible to define the array in the header file. Before doing this option then read this page. Here is some code that's compatible with both ISO C and GNU C:

// header file
extern int data_array[];

static inline int get_value(int index)
{
return data_array[index];
}

// source file
#include "header.h"

int data_array[32];

Get value of static variables in inline functions?

Your request for inlining is in some way incompatible with the internal linkage of the variable.

You have a static variable which means that this variable is only visible in that file.

On the other you have an inline function. If this function would be inlined somewhere else than in this file, then it would refer to another foo variable, which is probably not what you want; at least the compiler warns you about it. It suggests you to change the visibility of that function to static, as to only be available in the same entity than foo.

In another try, you add extern, but this is incompatible with static visibility, choose, extern or static. Read about linkage and visibility rules in C language, for more information.

You also suggest to add foo in some header, which is not a good idea, headers are reserved for declaration of objects not definition. You are encouraged to add type definition in headers, external declaration of objects; but discouraged from define objects (while not strictly forbidden, this would too often lead to clashes).

how to declare a static variable inside an inline function?

Yes you can, and they should* behave exactly the same as for a non-inline static local.

* Visual Studio 6 (yes, that ancient compiler) has a bug where if the inline function gets both inlined and non-inlined in different translation units the local will get constructed twice.

inline static variable in different translation units has different values(c++17)

static variables (as in your example) have internal linkage. There are 2 ways to achieve what you want, both of which are shown below. Also note that the static keyword has other meanings as well.

Method 1: C++17

With C++17, we can use the inline keyword as shown below:

header.h

#ifndef UNTITLED1_TEST_H
#define UNTITLED1_TEST_H

namespace t {
inline int i{0};//note the keyword inline here and initializer while keyword static has been removed

void inc() ;

void print_i() ;
}

#endif

header.cpp

#include "header.h"
#include <iostream>

//No need for initilaizing t::i here

void t::inc() {
t::i++;
}

void t::print_i() {
std::cout << t::i << std::endl;
}

main.cpp

#include <iostream>
#include"header.h"

int main() {
t::inc();

std::cout << t::i << std::endl; // -> output is: 1
t::print_i(); // -> output is : 1
}

The output of method 1 can be seen here.

Method 2: Pre-C++17

Here we make use of the extern keyword so that the variable can have external linkage.

main.cpp

#include <iostream>
#include"header.h"

int main() {
t::inc();

std::cout << t::i << std::endl; // -> output is: 1
t::print_i(); // -> output is : 1
}

header.h

#ifndef UNTITLED1_TEST_H
#define UNTITLED1_TEST_H

namespace t {
extern int i;//note the keyword extern and no initializer here

void inc() ;

void print_i() ;
}

#endif

Note I have removed added the static and inline keywords, and added the extern keyword. Now the variable has external linkage. Also, note that the initialization of t::i is done in header.cpp given below.

header.cpp

#include "header.h"
#include <iostream>

int t::i{}; //initialize t::i

void t::inc() {
t::i++;
}

void t::print_i() {
std::cout << t::i << std::endl;
}

Output of the above program is: Demo

1
1

Also, do note that the keyword static has other meanings as well. But I have answered according to the given example code snippet.

Static variables in inline function

As Oli indicates, your best bet is to simply look at the compiler output. However, here are some things to consider:

  • If the contents of the static are truly constant you will be better putting this in an anonymous namespace. This ensures its initialization has nothing to do with calling the function.
  • type of the static. Your example is quite trivial and thus will probably be fine, but other types will be different. Note that the initialization of such statics may or must be
    deferred until the block is entered (puzzle through the standard at 6.7 if you want)
  • Multi-threading, relating to the previous this initialization may be required to use a mutex to prevent multiple threads from doing the initialization.

Given the possible scenarios it'd be best to not have statics inside your function if you wish it to be inlined. But each compiler is different, and all types are not equal.

Whether the compiler can actually reduce this function to a compile-time constant is just an extended issue to whether it can inline the static at all. You may also wish to look at constexpr specifier if you can use C++11.



Related Topics



Leave a reply



Submit