Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most elegant way to share a C array

I have to turn back to (embedded) C after some lengthy time with C++, and have the following problem:

I have a source module which is included a lot of times, let's call it utilities.h and utilities.c In it, I have an important array, let's call it

#define IMPORTANT_ARRAY_LENGTH  10000
char important_array[IMPORTANT_ARRAY_LENGTH];

I have a lot of other functions in this utilities module, and they all work fine. However, in one of the other source files, let's call it worker.c, I have to use this array. What is the "official", elegant way to do this, without having to put extern char important_array[IMPORTANT_ARRAY_LENGTH] and the macro definition in the worker.c ?

If I do the following:

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;

then my array will be an undefined symbol in worker.c. If I don't use the extern keyword in utilities.h, then of course, it's a duplicate symbol. (Strangely, it compiles with just a warning, and I can see from the linker file that the size is allocated multiple times.)

Do I really have to declare my array in worker.c? I want to keep everything clean, and have all declarations in one place only: in a header file. And I want to have the macro definition only once (this is secondary, because I could use a const, but I want the preprocessor to handle it, and not take up place)

like image 440
vsz Avatar asked Feb 22 '12 12:02

vsz


4 Answers

What you have is the canonical way to do it: have an extern declaration in the header file, and define the variable in the .c file.

my array will be an undefined symbol in worker.c

No, it won't. Your code will compile and link just fine.

like image 89
NPE Avatar answered Nov 15 '22 04:11

NPE


I often put the definition in the header (this is frowned upon, I know). It keeps the definition and declaration close together, which is a Good Thing.

/* 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"

There is no risk of doing it wrong: the linker will complain if you do it wrong.

BTW a similar way to basically do the same, but maybe a bit more readable, is:

/* 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 */
like image 20
wildplasser Avatar answered Nov 15 '22 03:11

wildplasser


Having one declaration (extern...) in each translation unit and exactly one definition is the most elegant way to do this.

So leave the extern char important_array in the header and char important_array in one of the .c files.

like image 24
cnicutar Avatar answered Nov 15 '22 03:11

cnicutar


Create a new function at utilities.c called something like "get_important_array" that just returns a pointer to array and put the prototype at utilities.h. After that, when you put the utilities.h at worker.c you'll have important_array access in a simple, and organized way.

like image 28
Bruno Soares Avatar answered Nov 15 '22 04:11

Bruno Soares