Search code examples
carraysvariable-declarationavr-gcc

Best practice: declaring global arrays of fixed length automatically


I have a data structure that I want to share globally between files in the project.

mystruct_s data[] = {
    { // element 1
    }, { // element 2 ...
    }, { 0 } // element N is zero to mark array end
}

Within the same file, objects refer to data. Its type is read as mystruct_s[N]. This is nice and straighforward.

In the header file, I have:

mystruct_s data[];

In other files, I get a type mismatch warning, because it is assumed to mean a 1-element array.

I am counting length based on array contents, so I don't need to know sizeof. A good old fashioned pointer mystruct_s* would do.

  1. How can I propagate the length of the array into another file, automatically? This is a maintenance nightmare if I have to manually count every single element and put that count into the header.
    • Should I just declare it with some random-ass number anyway, and #pragma ignore the warning?
  2. How can I declare the array itself as an unknown or single-element array (any will do) or pointer?
    • I don't need a pointer variable, and it seems this is complicated by also doing this on the AVR platform, where the array shall be stored in PROGMEM. If I declare a pointer, it wants to put the pointer variable in PROGMEM. Which isn't very useful. And then the array it points to, becomes an unnamed object somewhere. (The compiler (GCC 8.1.0) doesn't like this, so I'm not sure what exactly it thinks I'm trying..)
  3. How should I approach this, if this is the wrong way? Throw everything in the header? (I do like to use header files for blocks of data, but I prefer to do that on blocks that I don't need to maintain; because these elements reference other objects in the .c file, it is more natural to place data[] there too.)

Solution

  • My preferred way to declare global variables and make them known in other modules is as follows:

    // to define global variables, use the following:
    
    // module.c
    #include "glo.h"
    
    // glo.h
    #ifndef EXTERN
    # define EXTERN extern
    #endif
    EXTERN int myvar;
    
    #define ARR_SIZE 123
    EXTERN int myArr[ARR_SIZE];
    
    // main.c
    #define EXTERN
    #include "glo.h"
    

    This alocates storage for the globals in main and makes them known as extern in all other modules.

    This expands to:

    // module.c
    extern int myvar;
    extern int myArr[123];
    

    and in main:

    // main.c allocates storage
    int myvar;
    int myArr[123];
    

    EDIT

    You have a requirement to know the array size not through a defined constant but as the size of the array based on the initializers.Possibly a good way is to define the array with a dummy size for all other modules and to provide the array size as a separate global variable that you initialize in main, after the initialization.

    // glo.h
    #ifndef EXTERN
    # define EXTERN extern
    extern int myArr[2];
    #endif
    EXTERN int gArrSize;
    

    and:

    // main.c
    #define EXTERN
    #include "glo.h"
    int myArr[] = { 1, 2, 3, 4, 0};
    int gArrSize= sizeof(myArr)/sizeof(myArr[0]);