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

时间:2014-02-14 05:59:29

标签: c++ gcc static inline

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

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

static int ply;

inline int WTM(){return ply;}

并在包含此头部的其他cpp文件中调用该函数。

cout << ply << " " << WTM();

奇怪的是,在调用此函数的地方,内联函数中的变量ply与函数外部之前的相同变量具有不同的值。

输出为0 1;

我检查了所有文件,plyWTM()只有这个单一的定义。

之后我将代码更改为以下内容:

static int ply;

static inline int WTM(){return ply;}

两个值变得相同。

我的编译器为g++ (GCC) 4.4.7,默认设置为。

我搜索了这个现象并得到了这两个链接: Difference between an inline function and static inline functionhttp://gcc.gnu.org/onlinedocs/gcc/Inline.html 但仍然不明白为什么会发生这种情况(特别是为什么他们在第一种情况下会有不同的价值观)。我想知道是否有人可以告诉我编译器将如何扩展这两段代码(我尝试使用-E但它似乎不能用于内联函数)。

4 个答案:

答案 0 :(得分:5)

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

当您将函数声明为static时,有什么不同,那就是它将在每个转换单元中定义与变量相同,因此只访问该转换单元的变量。

答案 1 :(得分:0)

首次使用没有静态的内联函数是未定义的行为。

标准3.2.6,

  

可以有多个......,...,内联函数的定义   与外部联系(7.1.2),...,在一个程序中提供每个   定义出现在不同的翻译单元中,并提供了   定义满足以下要求:

     

- D的每个定义应由相同的令牌序列组成;和

     

- 在D的每个定义中,查找相应的名称   根据3.4,应指在其中定义的实体   D的定义,或者指同一实体,

     

- ...

     

如果D的定义满足所有这些要求,那么   程序应该表现得好像有一个单一的定义D.如果   D的定义不满足这些要求,那么行为   未定义。

首次使用外部内联函数(无静态)时,名称查找后的ply名称引用不同翻译单元的实体。

答案 2 :(得分:0)

还有一个解释:

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

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

对代码大小的影响不太可预测;函数inline的对象代码可能更大或更小,具体取决于具体情况。

Inline函数是一种优化,它只在优化编译时才“有效”。如果你不使用-O,那么真正的函数不是inline

static inline function

当某个功能同时为inlinestatic时,

如果对函数的所有调用都集成到调用者中,并且从不使用函数的地址,则永远不会引用函数自己的汇编代码。

在这种情况下,compiler实际上不会输出函数的汇编代码,除非您指定选项-fkeep-inline-functions.

由于各种原因无法集成某些调用(特别是,无法集成函数定义之前的调用,也无法在定义中进行递归调用)

如果存在非集成调用,则该函数将照常编译为汇编代码。如果程序引用其地址,则必须像往常一样编译该函数,因为它不能是inlined

答案 3 :(得分:-1)

使用参考What's the difference between “static” and “static inline” function?

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

对于频繁调用的小功能,可以产生很大的性能差异。

然而,这只是一个“提示”,并且编译器可能会忽略它,并且大多数编译器将尝试“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*/};

这个紧密循环将在每次迭代时执行函数调用,并且函数内容实际上远小于编译器执行调用所需的代码。 inline将基本上指示编译器将上面的代码转换为等效的:

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

跳过实际的函数调用并返回

显然,这是一个展示要点的例子,而不是真正的代码。

static指的是范围。在C中,它表示函数/变量只能在同一个翻译单元中使用。