2011-09-08 117 views
2

我认为C语言中声明为静态的函数只在我定义的文件中可见。在以下示例中,静态变量在另一个文件中可见。我不是很确定如果是因为包括:c中的静态函数

的main.c:

#include "test.c" 

int main() { 
    test(); 
} 

test.c的:

static void test() { 
    // do something here 
} 

void foo() { 
    // do something different here 
} 

,如果它只有一个头文件的工作是不是完全没用吗?如果我想隐藏一个函数,那么我不会在头文件中提到它?!

+2

是的,这是因为包括。您应该只包含头文件'.h'。 – jweyrich

+0

@jweyrich:真的吗?预处理器对符号一无所知,它只是解析由chars组成的令牌。你能否解释一下#include一个c文件与直接粘贴它的内容有什么不同? –

+0

@flix请尝试仅包含* .h文件而非* .c文件。 – Allwyn

回答

7

#include是一个预处理指令。当预处理器(在编译之前运行)看到它时,它会将包含的文件的内容复制到那里。所以你最终在同一个文件中。

如果它只与头文件一起工作,那么它总是没用吗?如果我想隐藏一个函数,那么我不会在头文件中提到它?!

当然,但不是在头文件中提到它不会“隐藏”它。头文件没有被编译,如果你把你的原型放在那里,它就成为编译器的线索。

静态函数的优点是它们不会在文件外部可见,因为它在对象文件中不会是全局的。这允许您在其他文件中使用相同的符号(名称)作为另一件事,而不会发生冲突。

5

声明为静态的C中的函数仅在包含该函数的翻译单元中可见,这意味着符号不会被导出。它与文件无关,但与翻译单元无关。在你的情况下,有一个单独的翻译单元,它是main.c,它包含另一个文件的内容,用于定义main,test和foo; main和foo将被导出,而测试不会。

1

如果main.ctest.c是单独的翻译单元,那么您应该是正确的。但是,通过将test.c的文本直接包含到main.c中,您创建了一个单个转换单元,因此对于main可以看到静态函数。它的行为好像你已经将它全部写入一个文件一样

你不想#include包含变量或函数的文件定义;这是在编译或链接时遇到多个定义错误的好方法。相反,#include文件的内容应限于类型定义,非定义变量声明和函数声明。

如下您可以创建一个文件test.h

#ifndef TEST_H // include guard; prevents this file from being processed 
#define TEST_H // more than once per translation unit 

void foo();  // declaration for foo; this is the only function we're exposing 

#endif 

然后重写main.c作为

#include "test.h" 

int main(void) 
{ 
    test(); 
    return 0; 
} 

你会再编译main.ctest.c分开,然后链接生成的目标文件来创建可执行文件:

gcc -c main.c 
gcc -c test.c 
gcc -o test main.o test.o 

此时您将沿着“未定义参考”的顺序收到链接器错误,因为test的符号尚未导出。