C++ 内联函数中的静态变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/185624/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:32:29  来源:igfitidea点击:

static variables in an inlined function

c++headerlinkerinline-functions

提问by Dirk Groeneveld

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?

不管怎样,真正的问题是,这个函数内部的静态变量会发生什么?我最终会得到多少份?

回答by paercebal

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)

具有命名空间范围 (3.3.6) 的名称具有内部链接,如果它是

— 显式声明为静态的变量、函数或函数模板;

3.5/3 - C++14 (n3797)

当名称具有内部链接时,它表示的实体可以被同一翻译单元中其他作用域的名称引用。

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):

将其声明为 inline 使其成为内联的候选者(现在在 C++ 中这并不意味着很多,因为编译器会内联或不内联,有时会忽略关键字 inline 存在或不存在的事实):

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)

带有内联说明符的函数声明 (8.3.5, 9.3, 11.3) 声明了内联函数。内联说明符向实现表明,在调用点函数体的内联替换优先于通常的函数调用机制。不需要实现在调用点执行此内联替换;然而,即使省略了这种内联替换,7.1.2 中定义的内联函数的其他规则仍应遵守。

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)

extern 内联函数中的静态局部变量总是指向同一个对象。

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)

(默认情况下,函数是 extern,因此,除非您专门将函数标记为静态,否则这适用于该函数)

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

混合 inline 和 static 将产生您描述的结果(即使函数被内联,内部的静态变量也不会,并且您将获得与编译单元一样多的静态变量,包括静态函数的定义)。

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.

自从我写了这个问题,我就用 Visual Studio 2008 试过了。我试图打开所有使 VS 符合标准的选项,但我可能错过了一些。这些是结果:

当函数只是“内联”时,静态变量只有一个副本。

当函数为“静态内联”时,副本数与翻译单元数一样多。

现在真正的问题是事情是否应该是这样,或者这是否是 Microsoft C++ 编译器的特性。

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.

然后它对于每个编译单元来说都是“私有的”,这意味着每个 CPP 文件,包括声明静态函数的头文件,都将拥有自己的函数私有副本,包括自己的全局隐藏变量私有副本,因此变量与有编译单元,包括头文件。

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

所以 VC++ 的行为是正确的,你误解了“内联”和“静态”的真正含义。

回答by Mark Ransom

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.

像编译器一样思考片刻 - 不然怎么可能?每个编译单元(源文件)相互独立,可以单独编译;因此,每个人都必须创建变量的副本,并认为它是唯一的。链接器能够跨越这些边界并调整变量和函数的引用。

回答by Matt

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.

我发现 Mark Ransom 的回答很有帮助 - 编译器创建了静态变量的许多副本,但链接器选择一个副本并在所有翻译单元中强制执行它。

Elsewhere I found this:

在其他地方我发现了这个:

See [dcl.fct.spec]/4

见 [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.

[..] 具有外部链接的内联函数在所有翻译单元中应具有相同的地址。extern 内联函数中的静态局部变量总是指向同一个对象。extern 内联函数中的字符串文字是不同翻译单元中的相同对象。

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

我没有要检查的标准副本,但它符合我在 VS Express 2008 中检查程序集的经验

回答by Rapha?l Saint-Pierre

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.

应该是这样的。"static" 告诉编译器您希望该函数位于编译单元的本地,因此您希望每个编译单元一份副本,每个函数实例的静态变量副本一份。

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

"inline" 用于告诉编译器你希望函数被内联;现在,它只是把它当作“如果有多个代码副本就可以了,只要确保它是相同的功能”。所以每个人都共享静态变量。

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

注意:此答案是针对原始海报发布给自己的答案而写的。

回答by Dirk Groeneveld

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:

自从我写了这个问题,我就用 Visual Studio 2008 试过了。我试图打开所有使 VS 符合标准的选项,但我可能错过了一些。这些是结果:

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.

现在真正的问题是事情是否应该是这样,或者这是否是 Microsoft C++ 编译器的意识形态。

回答by Windows programmer

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.

内联意味着可执行代码(指令)被内联到调用函数的代码中。无论您是否要求,编译器都可以选择这样做。这对函数中声明的变量(数据)没有影响。

回答by Robert Gould

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)

除了这一切可能暗示的任何设计问题之外,因为您已经坚持使用它,所以在这种情况下您应该使用静态而不是内联。这样每个人都共享相同的变量。(静态函数)

回答by Jason Etheridge

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.

我相信你最终会得到一个翻译单元。您已经有效地获得了该函数的许多版本(及其声明的静态变量),每个包含标题的翻译单元都有一个版本。

回答by Jason Etheridge

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.

静态意味着一个副本分布在整个程序中,而内联意味着它在同一个程序中需要多次使用相同的代码,因此不可能在内联函数内部使变量静态化。