为什么我可以访问另一个文件中的静态变量?

时间:2019-11-11 23:12:40

标签: c static

我有2个文件:

a.c
b.c

a.c:

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

int main()
{
    printf("%s", B_VAR);
    return 0;
}

b.c:

static char B_VAR[] = "Hello world!\n";

编译并运行:

jonathan:~/code/staticDemo$ gcc a.c -o test
jonathan:~/code/staticDemo$ ./test
Hello world!

我的印象是,静态只会将B_VAR限制为b.c,但这似乎可行。

3 个答案:

答案 0 :(得分:1)

的确,static关键字使变量仅对单个C文件可见。但是,在a.c中,您 includes b.c意味着它没有经过编译并与a.c链接,而是被复制到a.c中。

C预处理程序在包含时将一个文件复制到另一个文件,并且在编译文件之前执行该预处理程序。

因此,这是要编译的有效代码(使用-e标志通过GCC生成,并且不包含<stdio.h>定义):

# 2 "a.c" 2
# 1 "./b.c" 1
static char B_VAR[] = "Hello world!\n";
# 3 "a.c" 2

int main()
{
    printf("%s", B_VAR);
    return 0;
}

这意味着B_VAR可在a.c中访问,因为它实际上在a.c中是。

如果您分别编译每个文件并将它们链接在一起以得到最终可执行文件,则B_VAR 不可访问。

示例(-c意味着仅进行预处理和编译,但不链接):

gcc -c a.c -o a.o (GCC失败,出现use of undeclared identifier 'B_VAR'

gcc -c b.c -o b.o

gcc a.o b.o -o test

./test

希望这会有所帮助。

答案 1 :(得分:0)

此处使用的static关键字使变量局部于“翻译单元”,而不是文件。 #include指令将指定文件的所有内容拉入当前的翻译单元。因此,可以访问B_VAR

要使用多个翻译单元创建程序,您可以跳过#include "b.c"并将两个源文件都提供给编译器驱动程序:

$ gcc a.c b.c -o test

通常的做法是永远不要#include源文件,而只标头文件。当项目变得更加复杂时,通过多个其他文件包含源文件将导致多个定义错误。

答案 2 :(得分:0)

文件a.c和b.c并非彼此独立地编译。您正在将b.c包含在a.c中。因此,对a.c进行预处理后,编译器将看到以下内容:

// contents of stdio.h
static char B_VAR[] = "Hello world!\n";

int main()
{
    printf("%s", B_VAR);
    return 0;
}

那么static的实际作用是使变量/函数对于所在的编译单元来说是本地的 ,可能包含一个或多个包含在一起的源文件。

>

如果您删除了包含文件并分别编译了这两个文件,则会看到错误。