【问题标题】:What is the use of declaring a static variable as extern inside a function?在函数内部将静态变量声明为 extern 有什么用?
【发布时间】:2012-03-13 14:37:12
【问题描述】:
#include <stdio.h>

static i = 5;

int main()
{
extern int i;
printf("%d\n",i);
return 0;
}

有人能给出在函数块内将静态变量声明为 extern 的任何用例吗?

新: 为什么不允许这样做?

int main()
{
static i = 5;
extern int i;
printf("%d\n",i);
return 0;
}

【问题讨论】:

  • 因为i 要么是外部的,要么是本地的——它不能同时是两者。
  • 不允许?你的第二个代码 sn-p 在我的 gcc(mingw) 上运行得很好
  • 我正在使用 gcc 4.1.2 20080704 (Red Hat 4.1.2-51),我收到以下错误:file1.c: In function âmainâ: file1.c:6: error: extern declaration âiâ 的声明遵循没有链接 file1.c:5:错误:âiâ 的先前定义在这里

标签: c


【解决方案1】:

当您需要访问驻留在另一个翻译单元中的变量而不全局公开外部变量时,这很有用(出于一些原因,例如名称冲突,或者变量不应该 可以直接访问,所以用static来限制它的作用域,但是那个TU的header还是需要访问的)。

例如,假设我们有一个翻译单元foo.c,它包含:

//foo.c
static int i = 0;

i 不应在 foo.c 之外更改或直接访问,但是,foo.h 需要访问 i 以实现内联函数,但 i 不应暴露给任何翻译单元使用foo.h,所以我们可以在功能层面使用extern,只在IncI的范围内暴露它,内联函数需要使用i

//foo.h
inline void IncI(int val)
{
    extern int i;
    i += val;
}

您的第二个示例是“不允许的”,因为编译器认为您正在尝试将两个不同的变量绑定到同一个符号名称,即:它在本地范围内创建 static i,但在全局范围内搜索 extern int i ,但没有找到,因为 static i 在函数范围内。一个更聪明的编译器只会修复与static i 的链接,无论这是否遵循我不知道的标准。


现在我有一个 C standards document 可以工作(我知道我很惭愧......),我们可以看到官方立场是什么(在 C99 中):

6.2.2 标识符的链接

第 3 节:

如果对象或函数的文件范围标识符的声明包含存储类 说明符静态,标识符有内部链接。

第 4 节:

对于使用存储类说明符 extern 声明的标识符 该标识符的先前声明可见的范围, 如果先前的声明指定了内部或外部链接,则 在后面的声明中标识符的链接与 在先前声明中指定的链接。如果没有事先声明 可见,或者如果先前的声明没有指定链接,则 标识符有外部链接。

因此,因为static 将导致内部链接,extern 会将链接带入当前范围。还有一个脚注说明这可能会导致变量隐藏:

23) 如 6.2.1 所述,后面的声明可能会隐藏前面的声明。

【讨论】:

  • @pezcode: static 可用于限制对象对翻译单元的可见性,但带有 inline 函数的标头可能需要访问静态变量,因此 extern 在函数级别开始发挥作用,因为函数可以访问变量而无需“全局”更改静态变量的可见性
  • @Necrolis: foo.h 最后包含什么?
  • @Necrolis:你举了一个有趣的例子,但我想知道它是否真的可以这样工作,因为如果其他翻译单元bar.c 也包含static int i = 0; 会发生什么? IncI() 中的 extern int i; 怎么知道要引用哪个 i?我不相信它可以。
  • @j_random_hacker:我不确定,我只使用过一次这种方法,后来我为了更好的方法而删除了它。您可能会看到编译器尝试根据名称和类型进行绑定,如果它无法选择一个,则会引发重新定义错误(除非使用 __declspec(selectany) 之类的东西)
  • @j_random_hacker:我用 C99 标准的相关部分更新了这个问题,解释了它的工作原理和一些陷阱。我确实同意这是一种不好的做法,但是,问题不是关于实践,而是关于它的使用。
【解决方案2】:

在第二种情况下,您告诉编译器您有一个静态(局部)变量i 和另一个(全局)变量i,它在其他地方定义。

【讨论】:

  • 因为在第一种情况下,static i = 5 在代码块之外,即。外部。
  • 我认为这是因为当我们在函数内部编写 static int i = 5 时,它没有链接。但是,在外部写入时,它具有内部链接。
  • 具有文件作用域的变量本质上是全局的,可以通过使用 extern 在其他文件中使用。当执行在另一个文件的另一个代码块中时,不能期望具有块范围的变量在范围内(即存在)。所以编译器需要一个名为 iint 但找不到它,因为它“隐藏”在代码块中
猜你喜欢
  • 2020-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
  • 1970-01-01
相关资源
最近更新 更多