14

I have several 450 element character arrays (storing bitmap data to display on lcd screens.) I would like to put them under a header file and #define them, but I keep getting compilation errors. How would I do this in C?

#define numbers[450] {0, 1,etc...}

#define numbers {0, 1, etc...}

#define numbers[450] then set the numbers later

and many more...

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Reid
  • 4,376
  • 11
  • 43
  • 75
  • 6
    Why don't you post the code that you have so far and what compiler errors you're getting? – Erik Dietrich Mar 23 '12 at 21:51
  • 2
    You can't `#define` something like that. Think about it; every time you use it you would be declaring a new array. Of course that will lead to multiple redefinitions. Macros are simply text substitution. Substitute the text yourself and see if it makes sense. – Ed S. Mar 23 '12 at 21:58

4 Answers4

16

Well... you certainly don't need to use a define. Just add them into the header as const, static arrays.

/* prevents multiple, redundant includes */
/* make sure to use a symbol that is fairly sure to be unique */
#ifndef TEST_H
#define TEST_H

/* your image data */
const char image[] = { 1, 2, 3, 4, ... };

#endif

Also, if you want help on a compilation error then you should post your code.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • Yes, but when the header is called more than once (It is needed in multiple parts of the program) I get errors. – Reid Mar 23 '12 at 21:52
  • 4
    Then you use an [include guard](http://en.wikipedia.org/wiki/Include_guard) and again, show examples. I don't know what it means to "call a header", but I assume you mean include. So, like I said... example. We're not psychic ya know. :) – Ed S. Mar 23 '12 at 21:53
  • Thanks. I will try the `#ifndef` I had not thought about that. – Reid Mar 23 '12 at 21:56
12

Because you are displaying on an LCD, I am assuming this is an embedded system.

Don't put the data into a header.

Put the data into an ordinary C or C++ file. Compile this. It might only contain the data, that is okay, and makes it easy to update.

Then use the header file to give access to the data.

For example, in a images.c file:

#include "images.h"
const byte numbers1[MAX_NUMBERS1] = { ... };
byte numbers2[MAX_NUMBERS2];       // will be initialsied to 0

Then images.h is:

#ifndef _IMAGES_H_
#define _IMAGES_H_

typedef unsigned char byte;
#define MAX_NUMBERS1 (450)
        // different constants in case you change something        
#define MAX_NUMBERS2 (450)      
       // even better if you can do const static int MAX_NUMBERS1=450; 
       // but depends on the compiler
extern const byte numbers1[MAX_NUMBERS1] = { ... };
extern byte numbers2[MAX_NUMBERS2];       // will be initialised to 0

#endif

Then all other .c files in the program can access them.

It is (almost) always a bad idea to put a definition of a variable into a header file.

A declaration of a variable, eg. extern byte numbers2[MAX_NUMBERS2]; is telling the C compiler that there is an array variable called numbers2 somewhere else in the final, linked program. If the linker doesn't get that definition (from somewhere else) then it will raise an error because there is no space for the variable allocated.

A definition of a variable (notice no extern), eg. byte numbers2[MAX_NUMBERS2]; is effectively telling the C compiler that there is an array variable called numbers2 and it should allocate the space here, in the resulting object code from this source file, and this will be used to hold the value of the variable in the final, linked program.

The space for numbers2 is not allocated by the C compiler when it sees a declaration (preceded by extern), it is allocated when it sees the actual definition (no extern).

So, if you put the actual definition of any variable in a header file, and include it into more than one source code files (.c), the C compiler will allocate space for the variable more than once. Then the linker will give an error (usually multiple definitions of the same name).

There is a more subtle problem. If, when first developing the program, the header file is only included is one source file, then the program will compile and link correctly. Then, at a later date, if a second source file includes the header (maybe someone has just split the original source code file into two files), the linker will raise a 'multiple definitions' error. This can be very confusing because the program used to compile and link, and apparently nothing has changed.

Summary
Never allocate space for a variable by putting a definition in a header file. Only put variable declarations in header files.

gbulmer
  • 4,210
  • 18
  • 20
  • is the reason not to include it in a header file, for the reason being it's an embedded system, that it will take more disk space? – Honinbo Shusaku Mar 31 '17 at 21:21
  • @Abdul - I hope that is clearer. If it is an embedded system, then it likely does not have disk. – gbulmer Apr 02 '17 at 01:37
  • where is the executable binary stored in embedded systems that don't have disks? – Honinbo Shusaku Apr 06 '17 at 14:56
  • I guess I was conflating disk memory, with flash memory. When I say disk space, I mean non-volatile storage space. – Honinbo Shusaku Apr 06 '17 at 15:06
  • 1
    @Abdul - The executable would usually be stored in on-chip flash memory for most microcontrollers (eg. ATmega, Arm Cortex-M) or external flash memory chips. The initial bootloading process for a PC is stored in Quad SPI Flash (https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus) on the motherboard, and when that runs on power up or reset, it starts to load the operating system from disk. – gbulmer Apr 08 '17 at 10:40
  • 1
    @Abdul - Minimising program size is about ensuring their is only one instance of data. Defining data in a header may either causes a failure when the program is linked, or may waste space. The linker will fail if it finds more than one instance of the data with the same name and it hasn't enough information to discard all but one. Or create more than one instance of the data. This is caused by including the header into several source code (.c) files having defined the data as 'static' in the header. ` The linker builds them into the executable program, wasting space (on disk and in memory). – gbulmer Apr 08 '17 at 10:49
  • @Abdul - your welcome. I'm very happy to try to help. – gbulmer Apr 08 '17 at 10:51
1

I have had a similar problem. In my case, I needed an array of constants in order to use as size of other static arrays. When I tried to use the

const int my_const_array[size] = {1, 2, 3, ... };

and then declare:

int my_static_array[my_const_array[0]];

I get an error from my compiler:

array bound is not an integer constant

So, finally I did the following (Maybe there are more elegant ways to do that):

#define element(n,d) ==(n) ? d :
#define my_const_array(i) (i) element(0,1) (i) element(1,2) (i) element(2,5) 0
Ojos
  • 51
  • 5
-1
#define ARRAY_SIZE 5
#define ARRAY (int[ARRAY_SIZE]){1, 2, 3, 4, 5}

but it seems like you need to have gcc v4.0 or above.

Codemaker2015
  • 12,190
  • 6
  • 97
  • 81
tonka
  • 1
  • 1