Search code examples
c99externvariable-declaration

extern declaration of array


I have an array with size determined during compile-time defined in a source file.

const int array[] = {1, 3, 3, 7};

The number of the elements could change in the future so I'd rather not hardcode it in the brackets.

This array needs to be accessed from several source files so I'm trying to add an extern declaration to it in a header. However I'm not sure this is possible due to the implicit array size. I tried two variants:

extern const int array[]; // Warning: size of symbol `array' changed from 8 to 16
extern const int *array; // error: conflicting types for 'array'

Is it possible to do this or should I look for a work-around?


Solution

  • In the header that declares the variable, write:

    extern const int array[];
    

    You're right, though, that the other files won't know the size of the array. That's trickier. You might perhaps use in the header:

    extern const int array[];
    extern const size_t array_size;
    

    and where the array is defined:

    const int array[] = {1, 3, 3, 7};
    const size_t array_size = sizeof(array) / sizeof(array[0]);
    

    You'd include the header where the array is defined to ensure that the cross-references are correct, in agreement. You'll get no complaint from me if you choose to use int instead of size_t (but if you set your compiler to fussy enough, it may have different views on the subject).

    Note that the array size is not a 'integer constant' within the meaning of the standard; it could not be used in a case label, for example. If you declare another array using array_size, it will be a VLA — variable length array. Such arrays cannot be declared at file scope (or with static storage class inside a function).

    See also How do I use extern to share variables between source files?

    Illustration

    An MCVE (Minimal, Complete, Verifiable Example) for the answer:

    ext-def.h

    #include <stddef.h>
    
    extern const int array[];
    extern const size_t array_size;
    

    ext-def.c

    #include "ext-def.h"
    
    const int array[] = {1, 3, 3, 7};
    const size_t array_size = sizeof(array) / sizeof(array[0]);
    

    ext-use.c

    #include "ext-def.h"
    #include <stdio.h>
    
    int main(void)
    {
        for (size_t i = 0; i < array_size; i++)
            printf("%zu: %d\n", i, array[i]);
        return 0;
    }
    

    Compilation

    Using GCC 7.2.0 on a MacBook Pro running macOS High Sierra 10.13.2, using the options specified by martinkunev in a comment:

    $ gcc -std=c99 -pthread -O2 -fstrict-aliasing -fomit-frame-pointer -pedantic -o ext-def ext-def.c ext-use.c
    $ ./ext-def
    0: 1
    1: 3
    2: 3
    3: 7
    $
    

    Using my default compilation options (C11 not C99):

    $ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -c ext-def.c
    $ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -c ext-use.c
    $
    

    Equally warning-free under either set of options. You can add -pedantic to the C11 command lines without getting any warning, too.