无论如何,真正的问题是,这个函数内的静态变量会发生什么?我最终会得到多少个副本?
自从我写了这个问题之后,我尝试在Visual Studio 2008中打开所有符合标准的选项,但我可能错过了一些。以下是结果:
当函数仅为“inline”时,只有一个静态变量的副本。
当函数为“static inline”时,有与翻译单元数量相同的副本。
真正的问题现在是事情是否应该是这样的,还是这是 Microsoft C++ 编译器的特异性。
所以我想你可能有类似于这样的东西:
void doSomething()
{
static int value ;
}
您必须意识到函数内的静态变量,简单来说,就是一个全局变量,但只对函数本身可见。
内联函数不会改变任何内容:
inline void doSomething()
{
static int value ;
}
只会有一个隐藏的全局变量。编译器尝试内联代码并不会改变只有一个全局隐藏变量的事实。
现在,如果您的函数被声明为静态:
static void doSomething()
{
static int value ;
}
这里的“private”是指对于每个编译单元都是私有的,这意味着包括声明静态函数的头文件在内的每个CPP文件都将拥有其自己的私有函数副本,包括其自己的全局隐藏变量的私有副本,因此变量数量与包含头文件的编译单元一样多。
在一个带有“static”变量的“static”函数中添加“inline”:
inline static void doSomething()
{
static int value ;
}
就静态变量而言,不添加“inline”关键字和添加“inline”关键字的结果是相同的。
因此,VC++的行为是正确的,您误解了“inline”和“static”的真正含义。
我相信编译器会创建许多变量的副本,但链接器会选择其中一份并使其他所有副本引用它。当我尝试创建不同版本的内联函数时,也得到了类似的结果; 如果该函数没有实际被内联(调试模式),则无论从哪个源文件调用,所有调用都转到同一个函数。
暂且假设自己是编译器 - 否则还能怎么做呢?每个编译单元(源文件)都独立于其他单元,可以单独编译;因此,每个编译单元都必须创建变量的副本,并认为该副本是唯一的。链接器有能力跨越这些边界,并调整变量和函数的引用。
-s -O2
编译)。clang v10.0.0也是如此。 - CR.应该是这样的。
"static"告诉编译器您希望函数局限于编译单元,因此您希望每个编译单元有一个副本和每个函数实例的静态变量的一个副本。
"inline"用于告诉编译器您希望将函数内联;现在,它只是将其视为“如果代码有几个副本,则可以”,只需确保是相同的函数即可。因此,每个人都共享静态变量。
注意:此答案是针对原始发布者自己发布的答案编写的。
inline
并不会 导致 内联,它只是建议内联,并允许有多个定义(但不能在同一编译单元中)。 - Raphaël Saint-Pierre静态意味着一份副本分布在整个程序中,但内联意味着在同一程序中需要多次使用相同的代码,因此不可能在内联函数内部使变量静态。
我相信你最终会得到每个翻译单元一个版本。实际上,你有许多版本的该函数(及其声明的静态变量),每个包含该头文件的翻译单元都有一个。
inline void doSomething() { static int value ; }
中,该函数具有外部链接;如果它出现在从两个不同单元包含的头文件中,则会违反 ODR。 - M.M