2012-02-22 75 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。