0

When writing C code, I might want to define a constant array in a header file so that it may be used in multiple .c files.

Take the following example:

main.c

#include <stdio.h>
#include "main.h"

int main() {
  int localmat[9];
  for (int i = 0; i < 9; i++) {
    localmat[i] = HEADERMAT[i];
  }
  matadd(localmat, HEADERMAT);
  return 0;
}

main.h

#ifndef _MAIN_H_
#define _MAIN_H_

// Constant array
const int HEADERMAT[9] = {0,1,2,3,4,5,6,7,8};

// prototype function:
void matadd(int matA[9], const int matB[9]);

#endif

functions.c

#include "main.h"

void matadd(int matA[9], const int matB[9]){
  for (int i = 0; i < 9; i++) {
    matA[i] += matB[i];
  }
}

The constant array HEADERMAT declared in main.h is used in both main.c and functions.h. The header does use ifndef to prevent redefinitions and yet, the compiler will still complain about it being defined multiple times:

/usr/bin/ld: /tmp/ccVWhI0u.o:(.rodata+0x0): multiple definition of `HEADERMAT'; /tmp/ccRAIQ5u.o:(.rodata+0x0): first defined here
collect2: error: ld returned 1 exit status

What would be the better way of making this array accessible to both C files?

Benjamin Chausse
  • 1,437
  • 2
  • 10
  • 20
  • See ["static const" vs "#define" vs "enum"?](https://stackoverflow.com/q/1674032/15168) for a discussion of simple scalar values as constants. An array is a different animal. You'll need to select a source file to define the array, and declare (but not define) it in the header. Or you have to define it as `static` in the header, but then you run into problems with repetition of the data (which may not matter for a 36-byte array but would definitely be a problem for an array of many kilobytes). You might be able to finagle the problems with an `inline` function, but it's tricky at best. – Jonathan Leffler Nov 19 '22 at 03:08

2 Answers2

0

Header files are for declarations. So, this is one way:

// main.h
#ifndef _MAIN_H_
#define _MAIN_H_

// Constant array
const int HEADERMAT[9]; // <---- declaration only
 
// prototype function:
void matadd(int matA[9], const int matB[9]);

#endif

Then, in some source file (preferably main.c, since we declared in main.h)

// main.c
#include <stdio.h>
#include "main.h"

const int HEADERMAT[9] = {0,1,2,3,4,5,6,7,8}; // <---- definition here

int main() {
  int localmat[9];
  for (int i = 0; i < 9; i++) {
    localmat[i] = HEADERMAT[i];
  }
  matadd(localmat, HEADERMAT);
  return 0;
}

If you did it this way in the header file instead:

// main.h
// main.h
#ifndef _MAIN_H_
#define _MAIN_H_

// Constant array
static const int HEADERMAT[9] = {0,1,2,3,4,5,6,7,8}; // <-- static definition

// prototype function:
void matadd(int matA[9], const int matB[9]);

#endif

Then the array would be duplicated in every source file that included main.h, which, as the Jonathan Leffler's comments point out, is not that big of a deal (36 bytes). But for an array of appreciable size, the waste would be a concern.

Mark Benningfield
  • 2,800
  • 9
  • 31
  • 31
0

If I understand you simply want to make the HEADERMAT[] array available in multiple source files, you can simply declare it as usual in any of the source files and then declare it as extern in any other source file that needs it.

To do so, you need to

  1. define a macro for the array size in a common header so all sources will know the size of the array, e.g. #define HEADERMATSZ 9,
  2. declare the array as usual in one of the C source files, e.g. const int HEADERMAT[HEADERMATSZ] = {0,1,2,3,4,5,6,7,8};,
  3. in any other C source files that need access, declare extern const int HEADERMAT[HEADERMATSZ];.

Now you can simply use HEADERMAT[] as needed in any file where it is either declared originally, or as extern.

A short example, first the common header to be included by main.c and source1.c that holds a function that will use the array declared as extern, e.g.

#ifndef COMMONHDR
#define COMMONHDR  1

#define HEADERMATSZ 9     /* defined size of extern array */

void showoutput (void);   /* declaration of function using extern array*/


#endif

For your main.c we will declare the array there, including the common header to provide the declaration for the function we will call from source1.c that uses the array declared extern, e.g.

#include <stdio.h>

#include "commonhdr.h"

const int HEADERMAT[HEADERMATSZ] = {0,1,2,3,4,5,6,7,8};


int main (void) {
  
  puts ("output from other file");
  showoutput();
}

(the showoutput() function being the function called from source1.c, also note HEADERMATSZ can be omitted if your initializer has the correct number of values -- including it ensures the array is sized correctly)

Finally the source1.c file we provide the function definition that uses the array extern,

#include <stdio.h>

#include "commonhdr.h"

extern const int HEADERMAT[HEADERMATSZ];

/* definition of function using extern array */
void showoutput (void)
{
  for (int i = 0; i < HEADERMATSZ; i++) {
    printf (" %d  %d\n", i, HEADERMAT[i]);
  }
}

Compile both sources into the final executable, e.g. with gcc,

gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast source1.c -o main main.c

Example Use/Output

$ ./main
output from other file
 0  0
 1  1
 2  2
 3  3
 4  4
 5  5
 6  6
 7  7
 8  8

This method works well regardless whether it is on your PC or programming a micro-controller. By using extern, the array need not be const and can be modified in either source if it is mutable.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85