我有两个文件。 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;
答案 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)
反例:
static int block_no = 0;
extern int increment(void);
int increment(void)
{
return block_no++;
}
#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
)是不正常的。可以有理由这样做,但它们是特殊情况,你描述的不是特殊情况之一。