10

我正在尝试一个小例子来了解静态外部变量及其用途。静态变量是局部范围的,外部变量是全局范围的。

静态5.c

#include<stdio.h>
#include "static5.h"
static int m = 25;
int main(){
 func(10);
 return 0;
}

静态5.h

#include<stdio.h>
int func(val){
 extern int m;
 m = m + val;
 printf("\n value is : %d \n",m);
}

gcc 静态5.c 静态5.h

o/p:

static5.c:3: error: static declaration of m follows non-static declaration
static5.h:3: note: previous declaration of m was here

已编辑

正确的程序:

a.c:
#include<stdio.h>
#include "a1_1.h"
int main(){
 func(20);
 return 0;
}

a1.h:
static int i = 20;

a1_1.h:
#include "a1.h"
int func(val){
 extern int i;
 i = i + val;
 printf("\n i : %d \n",i);
}

这很好用。但这被编译成单个编译单元。因此可以访问静态变量。在整个编译单元中,我们不能通过使用 extern 变量来使用静态变量。

4

4 回答 4

20

static有一个非常简单的逻辑。如果一个变量是static,则表示它是一个全局变量,但它的作用域仅限于它定义的地方(即只在那里可见)。例如:

  • 函数外:全局变量但仅在文件内可见(实际上是编译单元)
  • 函数内部:全局变量,但仅在函数内部可见
  • (C++) 类内部:全局变量,但仅对类可见

现在让我们看看 C11 标准对staticextern(强调我的)说了什么:

6.2.2.3

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

6.2.2.4

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

6.2.2.7

如果在翻译单元内,相同的标识符同时出现在内部和外部链接中,则行为未定义。

所以标准首先说,如果你有:

static int m;
extern int m;

然后第二个声明 (with extern) 将考虑第一个声明,最后m仍然是static.

但是,在任何其他情况下,如果存在具有内部和外部链接的声明,则行为未定义。这实际上给我们留下了一个选择:

extern int m;
static int m;

extern声明前static声明。在这种未定义行为的情况下,gcc 足以给你错误。

于 2013-06-11T12:06:13.847 回答
17

记住这一点(引用 Eli Bendersky 的话):

  • 函数内的静态变量在调用之间保持其值。
  • 静态全局变量或函数仅在其声明的文件中“可见”

在您的代码中,static int m = 25;意味着它m范围仅限于该文件,也就是说,它只在内部可见static5.c,其他任何地方都看不到。

如果您想在m外部使用,请static5.c确保static从变量的声明中删除关键字。

有关更规范的解释以及示例,请参阅Eli Bendersky 的此答案

编辑:(根据 Klas 的建议) **实际范围是编译单元,而不是源文件。编译单元是文件在预处理器步骤之后的样子

于 2013-06-11T10:11:33.903 回答
3

问题与错误消息中的说明完全相同。m被声明为正常int,但后来被定义为static int.

extern告诉编译器/链接器在全局变量表中查找变量。

static(在函数之外)告诉编译器从全局变量表中排除该变量。

你看到冲突了吗?

要解决此问题,请static从定义中删除关键字或将定义移到包含static5.h.

应该注意的是,您设计文件的方式并不是最佳实践。包含文件通常不包含函数。

于 2013-06-11T10:43:28.783 回答
2

在声明 m 时删除关键字 static ,错误将被删除,您将能够得到 50 的答案。 static 关键字使范围限制在文件中。

于 2013-06-11T10:19:05.587 回答