C中的静态和外部内联函数

时间:2018-01-09 16:09:32

标签: c

我试图详细了解静态和外部函数之间的区别。

我知道静态和外部内联函数之间的基本区别。

如果错误,请纠正我的理解:

  • 静态内联函数仅对定义它的翻译单元可见。
  • extern内联函数可以在多个翻译单元中访问。
  • 最好在头文件中定义内联函数
  • 静态和静态内联函数定义之间没有区别。

下面是一个示例代码,我对此行为感到困惑。

file1.c中

#include <stdio.h>
#include "file.h"

int main(void)
{
  fun1(); 
  return 0;  
}

static inline void fun1(void)
{
  int i;
  for (i = 0; i < 10; i++) {
      static int k = 20;
      printf("Value : %d \n", k++);
  }
}

file2.c中

#include <stdio.h>

inline void fun1(void)
{
  int i;
  int k = 0;
  for (i = 0; i < 10; i++) {
      printf("Value : %d \n", k++);
  }
}

file.h

#ifndef FILE_H
#define FILE_H 

extern inline void fun1(void);

#endif

当我编译上面的代码&#34; gcc file1.c file2.c&#34;时,从file2.c调用了fun1。这很清楚,因为fun1被声明为extern,它应该采用file2.c中的extern函数(默认情况下所有内联函数都是extern?)。

但是当我在file1.c中将静态内联函数更改为静态函数(static void fun1(void))时,从file1.c调用了fun1。可能是什么原因?

我也读过&#34;如果内联函数声明了外部链接但未在同一个翻译单元中定义,则行为未定义&#34;。但我不明白这一点。这可以用上面的例子来解释吗?

与C相比,C ++中的静态函数和外部函数之间是否存在差异?

1 个答案:

答案 0 :(得分:4)

您的代码不正确,因为您无法使用extern(默认值)声明函数,然后提供static定义。它完全编译的事实并不表示任何有用的东西。

从n1548§6.2.2:

  

如果在翻译单元中,同一标识符同时显示内部和外部链接,则行为未定义。

所以,你在file1.c中得到类似的东西:

// Has external linkage (which is the default!)
extern inline void fun1(void);

// This would also have external linkage.
inline void fun1(void);

// This has static linkage.
static inline void fun1(void) {
    ...
}

(注意:“外部链接”是默认值,但extern inline实际上意味着特殊内容,它与inline不同。)

的Bam!未定义的行为。编译器甚至可能不会给你一个错误信息,虽然有些编译器似乎给出了错误信息。

error: static declaration of 'func' follows non-static declaration

此错误实际上 nothing 与函数为inline的事实有关。带或不带inline的错误。

那些问题呢?

  

静态内联函数仅对定义它的翻译单元可见。

所有static函数都是如此。它们具有“内部链接”,因此您可以在一个文件中使用static void func(void);,在另一个文件中使用完全不同的static int func(char *p);inline在这里没有任何区别。

  

extern内联函数可以在多个翻译单元中访问。

是的,这就是为什么你不应该把它们放在头文件中。如果将它们放在头文件中,您将获得同一函数的多个不同定义,这些定义都可以从不同的转换单元访问。这是一个错误。相反,将extern inline放在源文件中,但它只需要是声明,而不是定义。

  

最好在头文件中定义内联函数

在其他地方定义内联函数没有任何意义。如果您的函数仅在一个文件中使用,则只需标记static,编译器将决定如何调用该函数。

  

静态和静态内联函数定义之间没有区别。

是的,没有区别。

嗯,从技术上讲,不,这是有区别的,因为允许编译器以static inline函数的方式处理static函数。但是,现代编译器倾向于使用自己的一组规则来决定内联函数,函数是否inline不会对该过程产生太大影响。

嗯,实际上还有另外一个区别。如果未使用static inline函数定义,则不会在GCC中生成警告,但static函数将会生成警告。这样您就可以在头文件中放置static inline函数。这是将inline放在头文件中的替代方法,这需要您在程序中的某处为该函数设置extern inline。但是,如果编译器决定不想内联你的static inline函数,或者因为它认为内联更糟或者因为内联是不可能的,那么它将不得不在每个文件中单独复制该函数。用于。

那么,你是如何正确地做到的?

如果函数static具有先前的非静态声明,则不要声明它。这是一个错误,即使它编译。<​​/ p>

不要在头文件中声明inline extern函数。这为函数创建了一个“外部定义”,您只能在整个程序中使用其中一个。

在未定义头文件的情况下,不要在头文件中声明inline个函数。没有意义。

以下是您希望如何执行此操作的方法:

mylib.h

// Provide "inline definition" of the function.
inline int times_two(int x) {
    return x * 2;
}

mylib.c

#include "mylib.h"

// Provide "external definition" of the function.
extern inline int times_two(int x);

这是自C99以来做事的标准方法。编译器应该可以自由地使用内部定义或外部定义,无论它认为哪个更好。如果您没有外部定义或者您有多个外部定义,则可能会出现链接错误,就像使用常规函数一样。

C ++对内联函数有着完全不同的规则。