静态声明m遵循非静态声明

Ang*_*gus 9 c

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

static5.c

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

static5.h

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

gcc static5.c static5.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
Run Code Online (Sandbox Code Playgroud)

EDITED

正确的程序:

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);
}
Run Code Online (Sandbox Code Playgroud)

这很好用.但是这被编译成一个单独的编译单元.因此能够访问静态变量.在编译单元中,我们不能通过使用extern变量来使用静态变量.

Sha*_*baz 17

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;
Run Code Online (Sandbox Code Playgroud)

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

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

extern int m;
static int m;
Run Code Online (Sandbox Code Playgroud)

extern宣布前的static声明.gcc非常好,在这种未定义行为的情况下会给你错误.


Nli*_*tis 16

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

  • 函数内的静态变量在调用之间保持其值.
  • 静态全局变量或函数仅在其声明的文件中"看到"

在你的代码,static int m = 25;意味着m范围仅限于该文件,也就是说,它是唯一可见的内部static5.c和其他地方.

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

有关更典型的解释,以及示例,请参阅Eli Bendersky的回答

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

  • 范围是编译单元,而不是源文件.编译单元是文件在预处理器步骤之后查看的方式,然后func位于同一文件中. (3认同)