静态变量的行为类似于C中的全局变量

时间:2014-03-06 07:37:03

标签: c

我有两个文件。 1.c和2.c

1.c中定义了一个静态变量。我可以通过在2.c中使用关键字extern来访问和修改2.c中的静态变量。这怎么可能?如果静态变量可以在这样的其他文件中访问,那么静态变量范围的目的是什么。

1.C

static int block_no;

2.C

extern int block_no;
block_no = 5;

2 个答案:

答案 0 :(得分:3)

你能做到这一点的唯一方法是,如果你以某种方式将两个标识符放在同一个翻译单元中(例如,如果2.c执行#include "1.c")。

标准的相关部分是6.2.2 Linkages of identifiers (a),从/2开始:

  

2在构成整个程序的翻译单元和库的集合中,具有外部链接的特定标识符的每个声明表示相同的对象或功能。在一个翻译单元内,具有内部链接的标识符的每个声明表示相同的对象或功能。没有链接的标识符的每个声明都表示一个唯一的实体。

     

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

     

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

如果您将它们合并为一个翻译单元,则第4点将是相关的。如果您正在单独编译它们,那么两个block_no变量将是不同的,因为static变量将具有内部链接。

这并不是说没有定义的block_no 在其他地方与外部链接可能被拾取。否则,您的编译器应该抱怨block_no中缺少2.c,因为当该文件声明变量时,它不会定义它(“声明“表示声明它存在于其他地方”,“定义”表示实际在此处创建它。)


(a)这是来自C99,但快速浏览C11表明它没有改变。

答案 1 :(得分:1)

反例:

在f1.c

static int block_no = 0;

extern int increment(void);

int increment(void)
{
    return block_no++;
}

f2.c

#include <stdio.h>

extern int block_no;
extern int increment(void);

int main(void)
{
    for (int i = 0; i < 10; i++)
    {
        block_no = 5;
        printf("Extern block_no: %d; incremented block_no = %d\n",
               block_no, increment());
    }
    return 0;
}

编译时,代码不链接:

$ gcc -std=c11 -o f f1.c f2.c
Undefined symbols for architecture x86_64:
  "_block_no", referenced from:
      _main in ccwFyiSK.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
$

这是预期的行为。你必须编写类似的简单代码来重现麻烦。

int block_no;添加到f2.c的末尾允许代码编译和运行,生成:

Extern block_no: 5; incremented block_no = 0
Extern block_no: 5; incremented block_no = 1
Extern block_no: 5; incremented block_no = 2
Extern block_no: 5; incremented block_no = 3
Extern block_no: 5; incremented block_no = 4
Extern block_no: 5; incremented block_no = 5
Extern block_no: 5; incremented block_no = 6
Extern block_no: 5; incremented block_no = 7
Extern block_no: 5; incremented block_no = 8
Extern block_no: 5; incremented block_no = 9

另一种让它“工作”的方法是f2.c的变体:

#include <stdio.h>
#include "f1.c"

extern int block_no;
extern int increment(void);

int main(void)
{
    for (int i = 0; i < 10; i++)
    {
        block_no = 5;
        printf("Extern block_no: %d; incremented block_no = %d\n", block_no, increment());
    }
    return 0;
}

这样的输出很乏味:

Extern block_no: 6; incremented block_no = 5
…
Extern block_no: 6; incremented block_no = 5

请注意,在其他C源文件中包含C源文件(file.c)是不正常的。可以有理由这样做,但它们是特殊情况,你描述的不是特殊情况之一。