2012-02-22 15 views
3

我有一些冗長的時間與C++之後回頭(嵌入)C,並有以下問題最優雅的方式,讓我們稱之爲utilities.hutilities.c 在這裏面,我有一個重要的陣列,我們稱之爲分享C數組

#define IMPORTANT_ARRAY_LENGTH 10000 
char important_array[IMPORTANT_ARRAY_LENGTH]; 

我有很多的其他功能這個utilities模塊中,他們都做工精細。然而,在其他源文件中的一個,我們稱之爲worker.c,我不得不使用這個數組。什麼是「官方」的,優雅的方式來做到這一點,而不必把extern char important_array[IMPORTANT_ARRAY_LENGTH],並在worker.c宏定義?

如果我做到以下幾點:

utilities.h

#ifndef _UTILITIES_H_ 
#define _UTILITIES_H_ 

#define IMPORTANT_ARRAY_LENGTH 10000 
extern char important_array[IMPORTANT_ARRAY_LENGTH]; 

// ... 

utilities.c

#ifndef _UTILITIES_C_ 
#define _UTILITIES_C_ 

#include "utilities.h" 

char important_array[IMPORTANT_ARRAY_LENGTH]; 

// ... 

worker.c

#include "utilities.h" 
// ... 
important_array[0] = 0; 

那麼我的陣列將是一個未定義的符號在worker.c。如果我不utilities.h使用extern關鍵字,那麼當然,這是一個重複的符號。 (奇怪的是,它只編譯了一個警告,我可以從鏈接文件中看到大小被分配多次。)

我真的必須在worker.c中聲明我的數組嗎?我想保持一切都乾淨,並且只將所有聲明放在一個地方:在一個頭文件中。我想有宏定義只有一次(這是次要的,因爲我可以用一個常量,但我想預處理器來處理它,而不是佔用的地方)

+0

在'utilities.h'聲明它。如果編譯器抱怨「未定義符號」,那麼你有另一個問題。你如何編譯它? – asaelr 2012-02-22 12:59:27

+0

我確實在'utilities.h'中聲明瞭它。我的問題是關於'worker.c'。 – vsz 2012-02-22 13:23:17

+1

順便說一句:不要在預處理符號中使用前導下劃線,除非你是實現的一部分。 – wildplasser 2012-02-22 13:28:40

回答

3

你有什麼是規範的方法:在頭文件中有一個extern聲明,並在.c文件中定義變量。

我的陣列將處於worker.c

沒有一個未定義的符號,它不會。你的代碼會編譯和鏈接就好了。

+0

這不是問題。正如你所看到的,我已經這樣做了。問題是關於如何在另一個翻譯單元中使用它。 – vsz 2012-02-22 13:30:06

+0

@vsz:你只要繼續使用它;沒有什麼可以做的了。我已經更新了答案。 – NPE 2012-02-22 13:32:07

+1

@vzs那麼,你的問題是關於最優雅的方式來做到這一點。用這種方法,你只需#include頭文件。由於這不適合你,你在其他地方做錯了什麼,或者你的編譯器壞了。 – nos 2012-02-22 13:34:03

2

有一個聲明(extern...)在每個翻譯單位和正好一個定義是最優雅的方式來做到這一點。

因此,將extern char important_array保留在標題中,char important_array保留在.c文件之一中。

+0

我知道,但這並不回答我的問題。我是否必須將'extern char important_array'放在** all **包含頭文件的'.c'文件中? – vsz 2012-02-22 13:21:02

+0

@vsz它確實回答你的問題。聲明在標題中,定義在一個.c文件中。再讀第二行? – cnicutar 2012-02-22 13:22:50

+0

@cnicutar:顯然,它沒有。在我寫的例子中,我在頭文件中定義了聲明,'.c'文件中的定義,並且在翻譯單元中包含了我想要使用它的頭文件,但仍然出現'undefined symbol'錯誤,儘管我包含標題。這個頭文件也包含在其他單元中,所以可能是這個翻譯單元(在我的例子中爲'worker.c'),由於#define _UTILITIES_H_ – vsz 2012-02-22 13:28:18

2

我經常把這個定義放在標題裏(我知道這是令人不悅的)。 它使定義和聲明保持在一起,這是一件好事。

/* file.c */ 
#define FILE_C 1 
#include "file.h" 

/* file.h */ 
#ifndef FILE_H 
#define FILE_H 1 

#define BIG_SIZE 13 

#if FILE_C 
char the_array[BIG_SIZE]; 
#else 
extern char the_array[BIG_SIZE]; 
#endif 

#endif /* FlLE_H */ 

/* other_file.c */ 
#include "file.h" 

沒有錯誤的風險:如果你做錯了,鏈接器會報錯。

BTW以類似的方式基本上做的是一樣的,但也許有點更具可讀性,是:

/* file.h */ 
#ifndef FILE_H 
#define FILE_H 1 

#if FILE_C 
#define EXTERN /**/ 
#else 
#define EXTERN extern 
#endif 

#define BIG_SIZE 13 

EXTERN char the_array[BIG_SIZE]; 

... 

#undef EXTERN 
#endif /* FlLE_H */ 
+0

你可以使用一個宏名稱,比如'AND_ALSO_DEFINE_STUFF'(或者那個單詞)而不是'FILE_C'。只是讓file.c明確告訴頭,可以提供的定義,而不是使它看起來像file.h是知道.c文件,他們應該是在一個。 – 2012-02-22 14:02:50

+0

這也是一種可能性,它只是一個名字。 ALSO_DIFINE的東西不是一個很有代表性的名字。我更喜歡DO_DEFINE_THE_BIG_ARRAY。但是,如果在.h文件中定義了多個項目,該怎麼辦? FILE_C宏名稱直接指示它應該被定義的位置,這也是一件好事。因人而異。 – wildplasser 2012-02-22 14:12:08

1

創建於utilities.c一個新的函數調用像「get_important_array」,它只是返回一個指針數組並將這個原型放在utilities.h中。之後,當您將utilities.h放在worker.c中時,您將以簡單且有組織的方式訪問important_array。