2011-09-08 115 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的符號尚未導出。