C++ 访问静态变量时内联函数和静态内联函数之间的差异

C++ 访问静态变量时内联函数和静态内联函数之间的差异,c++,gcc,static,inline,C++,Gcc,Static,Inline,在阅读其他代码时,我遇到了一个有趣的案例 在头文件中,定义的静态变量和内联函数简化如下: static int ply; inline int WTM(){return ply;} 该函数在包含该头的其他cpp文件中调用 cout << ply << " " << WTM(); 这两个值变得相同 我的编译器是带有默认设置的g++(GCC)4.4.7 我搜索了这个现象,找到了两个链接: 和 但仍然不明白为什么会发生这种情况(特别是为什么他们在第一种情况下会

在阅读其他代码时,我遇到了一个有趣的案例

在头文件中,定义的静态变量和内联函数简化如下:

static int ply;

inline int WTM(){return ply;}
该函数在包含该头的其他
cpp
文件中调用

cout << ply << " " << WTM();
这两个值变得相同

我的编译器是带有默认设置的
g++(GCC)4.4.7

我搜索了这个现象,找到了两个链接: 和
但仍然不明白为什么会发生这种情况(特别是为什么他们在第一种情况下会有不同的价值观)。我想知道是否有人能告诉我编译器将如何扩展这两段代码(我尝试使用
-E
,但它似乎不适用于内联函数)。

这是因为静态变量将在包含头文件的所有翻译单元中单独定义,但(非静态)变量函数将只定义一次。因此,变量有多个副本,但函数只有一个副本。函数将使用变量的哪个副本?我不知道,我认为要么是未定义的行为,要么是定义了实现(必须阅读规范)


当您将函数声明为
静态
时,不同之处在于,它将在每个转换单元中定义为与变量相同,因此,只访问该翻译单元的变量。

这是因为静态变量将在包含头文件的所有翻译单元中单独定义,但(非静态)函数将只定义一次。因此,变量有多个副本,但函数只有一个副本。函数将使用变量的哪个副本?我不知道,我认为要么是未定义的行为,要么是定义了实现(必须阅读规范)

将函数声明为静态函数时的不同之处在于,它将在每个转换单元中定义为与变量相同的变量,因此仅访问该转换单元的变量。

使用引用:

inline
指示编译器尝试将函数内容嵌入调用代码,而不是执行实际调用

对于经常调用的小函数,它们可能会产生很大的性能差异

但是,这只是一个“提示”,编译器可能会忽略它,并且大多数编译器会尝试“
内联”
,即使在可能的情况下,作为优化的一部分,不使用关键字

例如:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};
static int Inc(int i){return i+1};
.... // 一些代码
int i;
.... // 还有代码吗
对于(i=0;i使用参考:

inline
指示编译器尝试将函数内容嵌入调用代码,而不是执行实际调用

对于经常调用的小函数,它们可能会产生很大的性能差异

但是,这只是一个“提示”,编译器可能会忽略它,并且大多数编译器会尝试“
内联”
,即使在可能的情况下,作为优化的一部分,不使用关键字

例如:

static int Inc(int i) {return i+1};
.... // some code
int i;
.... // some more code
for (i=0; i<999999; i = Inc(i)) {/*do something here*/};
static int Inc(int i){return i+1};
..//一些代码
int i;
..//还有一些代码吗

对于(i=0;i您第一次使用不带static的内联函数是未定义的行为

标准3.2.6

内联函数可以有多个定义 程序中的外部链接(7.1.2),…,前提是 定义显示在不同的翻译单元中,并提供 定义满足以下要求:

-D的每个定义应包含相同的令牌序列;以及

-在D的每个定义中,查找对应的名称 根据第3.4条,应指本协议中定义的实体 D的定义,或应指同一实体

-

如果D的定义满足所有这些要求,则 程序的行为应与D的定义相同。如果 D的定义不满足这些要求,那么行为 没有定义


对于您第一次使用外部内联函数(无静态),在名称查找后,ply的名称指不同翻译单元的不同实体。

您第一次使用无静态的内联函数是未定义的行为

标准3.2.6

内联函数可以有多个定义 程序中的外部链接(7.1.2),…,前提是 定义显示在不同的翻译单元中,并提供 定义满足以下要求:

-D的每个定义应包含相同的令牌序列;以及

-在D的每个定义中,查找对应的名称 根据第3.4条,应指本协议中定义的实体 D的定义,或应指同一实体

-

如果D的定义满足所有这些要求,则 程序的行为应与D的定义相同。如果 D的定义不满足这些要求,那么行为 没有定义


对于您第一次使用外部内联函数(无静态),在名称查找后,ply的名称指的是不同翻译单位的不同实体。

对此还有一个解释:

通过声明函数
内联
, 您可以指示编译器将该函数的代码集成到其调用方的代码中

这通过消除函数调用开销使执行更快; 此外,如果任何实际参数值是常量,那么它们的已知值可能允许在编译时进行简化,因此不需要包含所有内联函数的代码

影响
 int i;
 ....
 for (i=0; i<999999; i = i+1) { /* do something here */};