This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Arrays in contiguous space

Hi all,
I have several const arrays of structures, of variable length.
I would like to store them in contiguous space, to use them as separate arrays or as an unique single big array.
Does exist in RealView C an "Keep variables in order" switch like in C166?
Is there any other way to "group" several arrays of homogeneous entities into one single big array without defining it twice?
Thank you for any comment/suggestion
Bruno

#include <stdint.h>

uint16_t var11;
uint16_t var12;
uint16_t var13;
uint16_t var14;
uint16_t var15;

uint16_t var21;
uint16_t var22;
uint16_t var23;

uint16_t var31;
uint16_t var32;

typedef struct
{
void *ptr;
uint16_t size;
uint16_t min;
uint16_t max;
uint16_t def;
} Parameter_t;

/*
3 arrays of same type, Parameter_t
does it exist any "pragma" to force the compiler to allocate
the following 3 arrays in contiguous space and in the same order?
I need both: 3 arrays and a single big one containing all of them
in the same order
*/

Parameter_t const Parlist1 [] =
{
{&var11, sizeof(var11), 0, 100, 20},
{&var12, sizeof(var12), 0, 100, 20},
{&var13, sizeof(var13), 0, 100, 20},
{&var14, sizeof(var14), 0, 100, 20},
{&var15, sizeof(var15), 0, 100, 20},
};


Parameter_t const Parlist2 [] =
{
{&var21, sizeof(var21), 0, 100, 20},
{&var22, sizeof(var22), 0, 100, 20},
{&var23, sizeof(var23), 0, 100, 20},
};


Parameter_t const Parlist3 [] =
{
{&var31, sizeof(var31), 0, 100, 20},
{&var32, sizeof(var32), 0, 100, 20},
};

/*
one BIG array containing all the previous variables in the same order.
ideally, having "labels" would just achieve the desired result: it would be
possible to define pointers into some array elements
*/

Parameter_t const ParlistAll [] =
{
// ParListPtr1: Beginning of ParList1
{&var11, sizeof(var11), 0, 100, 20},
{&var12, sizeof(var12), 0, 100, 20},
{&var13, sizeof(var13), 0, 100, 20},
{&var14, sizeof(var14), 0, 100, 20},
{&var15, sizeof(var15), 0, 100, 20},

// ParListPtr2: Beginning of ParList2
{&var21, sizeof(var21), 0, 100, 20},
{&var22, sizeof(var22), 0, 100, 20},
{&var23, sizeof(var23), 0, 100, 20},

// ParListPtr3: Beginning of ParList3
{&var31, sizeof(var31), 0, 100, 20},
{&var32, sizeof(var32), 0, 100, 20},
};

Parents
  • I think I would do it the reverse way:

    #include <stdint.h>
    #include <stddef.h>
    #include <stdio.h>
    
    #define TRUE 1
    #define FALSE 0
    #define NELEM(arr) (sizeof(arr)/sizeof(*(arr)))
    
    uint16_t var11;
    uint16_t var12;
    uint16_t var13;
    uint16_t var14;
    uint16_t var15;
    
    uint16_t var21;
    uint16_t var22;
    uint16_t var23;
    
    uint16_t var31;
    uint16_t var32;
    
    typedef struct {
        void *ptr;
        uint16_t size;
        uint16_t min;
        uint16_t max;
        uint16_t def;
    } Parameter_t;
    
    /// \brief Full set of parameters defined in one big array.
    Parameter_t parameters[] = {
        // Parameters for xxx
        {&var11, sizeof(var11), 0, 100, 20},
        {&var12, sizeof(var12), 0, 100, 20},
        {&var13, sizeof(var13), 0, 100, 20},
        {&var14, sizeof(var14), 0, 100, 20},
        {&var15, sizeof(var15), 0, 100, 20},
        {NULL},
    
        // Parameters for yyy
        {&var21, sizeof(var21), 0, 100, 20},
        {&var22, sizeof(var22), 0, 100, 20},
        {&var23, sizeof(var23), 0, 100, 20},
        {NULL},
    
        // Parameters for zzz
        {&var31, sizeof(var31), 0, 100, 20},
        {&var32, sizeof(var32), 0, 100, 20},
        {NULL},
    };
    
    /// \brief Pointers to start of the individual parameter lists.
    Parameter_t *parameterlists[3];
    
    /// Scan through parameters to find start index for the individual lists.
    unsigned prepare_list(void) {
        Parameter_t *p;
        unsigned src_idx = 0,num_lists = 0;
        char last_was_null = TRUE;
    
        for (p = parameters; src_idx < NELEM(parameters); p++,src_idx++) {
            if (last_was_null) {
                // First entry after termination of previous list.
                if (num_lists < NELEM(parameterlists)) {
                    parameterlists[num_lists++] = p;
                } else {
                    // parameterlists[] too small!
                    printf("'parameterlists' too small\n");
                    break;
                }
            }
            last_was_null = p->ptr == NULL;
        }
        if (!last_was_null) {
            // parameters[] should have ended with a termination!
            printf("parameters[] did not end with NULL entry.\n");
            if (num_lists) parameterlists[--num_lists] = NULL;
        }
        return num_lists;
    }
    
    int main(void) {
        unsigned i,n;
        Parameter_t *p;
    
        n = prepare_list();
        printf("Found %u lists\n",n);
        for (i = 0; i < n; i++) {
            p = parameterlists[i];
            if (p) {
                printf("List start %p %p %u %u %u %u\n",p,p->ptr,p->size,p->min,p->max,p->def);
            } else {
                printf("List start NULL\n");
            }
        }
        printf("var11 @ %p\n",&var11);
        printf("var21 @ %p\n",&var21);
        printf("var31 @ %p\n",&var31);
        return 0;
    }
    

Reply
  • I think I would do it the reverse way:

    #include <stdint.h>
    #include <stddef.h>
    #include <stdio.h>
    
    #define TRUE 1
    #define FALSE 0
    #define NELEM(arr) (sizeof(arr)/sizeof(*(arr)))
    
    uint16_t var11;
    uint16_t var12;
    uint16_t var13;
    uint16_t var14;
    uint16_t var15;
    
    uint16_t var21;
    uint16_t var22;
    uint16_t var23;
    
    uint16_t var31;
    uint16_t var32;
    
    typedef struct {
        void *ptr;
        uint16_t size;
        uint16_t min;
        uint16_t max;
        uint16_t def;
    } Parameter_t;
    
    /// \brief Full set of parameters defined in one big array.
    Parameter_t parameters[] = {
        // Parameters for xxx
        {&var11, sizeof(var11), 0, 100, 20},
        {&var12, sizeof(var12), 0, 100, 20},
        {&var13, sizeof(var13), 0, 100, 20},
        {&var14, sizeof(var14), 0, 100, 20},
        {&var15, sizeof(var15), 0, 100, 20},
        {NULL},
    
        // Parameters for yyy
        {&var21, sizeof(var21), 0, 100, 20},
        {&var22, sizeof(var22), 0, 100, 20},
        {&var23, sizeof(var23), 0, 100, 20},
        {NULL},
    
        // Parameters for zzz
        {&var31, sizeof(var31), 0, 100, 20},
        {&var32, sizeof(var32), 0, 100, 20},
        {NULL},
    };
    
    /// \brief Pointers to start of the individual parameter lists.
    Parameter_t *parameterlists[3];
    
    /// Scan through parameters to find start index for the individual lists.
    unsigned prepare_list(void) {
        Parameter_t *p;
        unsigned src_idx = 0,num_lists = 0;
        char last_was_null = TRUE;
    
        for (p = parameters; src_idx < NELEM(parameters); p++,src_idx++) {
            if (last_was_null) {
                // First entry after termination of previous list.
                if (num_lists < NELEM(parameterlists)) {
                    parameterlists[num_lists++] = p;
                } else {
                    // parameterlists[] too small!
                    printf("'parameterlists' too small\n");
                    break;
                }
            }
            last_was_null = p->ptr == NULL;
        }
        if (!last_was_null) {
            // parameters[] should have ended with a termination!
            printf("parameters[] did not end with NULL entry.\n");
            if (num_lists) parameterlists[--num_lists] = NULL;
        }
        return num_lists;
    }
    
    int main(void) {
        unsigned i,n;
        Parameter_t *p;
    
        n = prepare_list();
        printf("Found %u lists\n",n);
        for (i = 0; i < n; i++) {
            p = parameterlists[i];
            if (p) {
                printf("List start %p %p %u %u %u %u\n",p,p->ptr,p->size,p->min,p->max,p->def);
            } else {
                printf("List start NULL\n");
            }
        }
        printf("var11 @ %p\n",&var11);
        printf("var21 @ %p\n",&var21);
        printf("var31 @ %p\n",&var31);
        return 0;
    }
    

Children
  • Thank you for all your suggestions; as I explained in my initial post, I am just trying to have a double view of the same set of data.
    Data are organized in records and records are be grouped in arrays.
    This is a generic database of an application; my application is divided in different parts (tasks) and each task has his own set (array) of data.
    Each record in my database describes one application parameter, with pointer to data space, type, min, max and default values.
    I would like to manage my database in two different forms: each task should have access only to its own parameter set, while the startup task can access the whole set (to initialize it, loading all the values from nonvolatile storage).
    I already arrived to the solution proposed by Per, but I am always trying to search for something more "elegant".
    Yes, I can define pointers to each part of the array and initialize them at run time as suggested, but there should be a more elegant way to let the preprocessor do it.
    I want to do something very generic to reuse the code and I don't want to be forced to specify the array length: this can lead to errors.
    Maybe in a second time I will add some parameters and I don't want to be forced to change things in multiple places, I just want to add a single line to my database and the preprocessor should compute all the numbers.
    Having "labels" into array would solve this, but C language doesn't have them.
    It's more a philosophical issue than a real problem, I already solved it in several different ways, but all of them is really non elegant.
    I am just trying to force the preprocessor to do what I want to do. But I don't know how.... :-)))
    Once again, thank you all for your replies.
    Bruno

  • I would like to manage my database in two different forms: each task should have access only to its own parameter set, while the startup task can access the whole set (to initialize it, loading all the values from nonvolatile storage).

    Why not have separate perameter sets and an array of pointers to those parameter sets as the 'labels'? I don't think the additional level of indirection would be that bad. You could even store the sizes of the parameter sets in the array with the labels.

    I want to do something very generic to reuse the code and I don't want to be forced to specify the array length: this can lead to errors.

    Well, generic solutions often come at a price: the code tends to become unnecessarily complicated. So you have to balance things.
    What you are describing can be done with preprocessor. One way would be to use redefined macros and multiple inclusions. But the code would look horrible. There would have to be a very good reason to use this technique.
    As for having to specify lengths and subsequent errors, one way of dealing with them is assertions. Run-time assert() is part of the standard library. You could also have compile-time assertions:
    www.ddj.com/.../184401873

    Regards,
    - mike

  • The preprocessor solution:

    #include <stdint.h>
    
    uint16_t var11;
    uint16_t var12;
    uint16_t var13;
    uint16_t var14;
    uint16_t var15;
    
    uint16_t var21;
    uint16_t var22;
    uint16_t var23;
    
    uint16_t var31;
    uint16_t var32;
    
    typedef struct
    {
            void *ptr;
            uint16_t size;
            uint16_t min;
            uint16_t max;
            uint16_t def;
    } Parameter_t;
    
    #define PARAM_INIT(a, b, c, d, e) {(a),(b),(c),(d),(e)},
    
    #define PARLIST1 \ 
            PARAM_INIT(&var11, sizeof(var11), 0, 100, 20)\ 
            PARAM_INIT(&var12, sizeof(var12), 0, 100, 20)\ 
            PARAM_INIT(&var13, sizeof(var13), 0, 100, 20)\ 
            PARAM_INIT(&var14, sizeof(var14), 0, 100, 20)\ 
            PARAM_INIT(&var15, sizeof(var15), 0, 100, 20)
    
    #define PARLIST2 \ 
            PARAM_INIT(&var11, sizeof(var21), 0, 100, 20)\ 
            PARAM_INIT(&var12, sizeof(var22), 0, 100, 20)\ 
            PARAM_INIT(&var13, sizeof(var23), 0, 100, 20)
    
    #define PARLIST3 \ 
            PARAM_INIT(&var11, sizeof(var21), 0, 100, 20)\ 
            PARAM_INIT(&var12, sizeof(var22), 0, 100, 20)
    
    Parameter_t const Parlist [] = { PARLIST1 PARLIST2 PARLIST3 };
    
    #undef PARAM_INIT
    #define PARAM_INIT(a, b, c, d, e) + 1
    
    #define Parlist1 (Parlist)
    #define Parlist2 (Parlist1 PARLIST1)
    #define Parlist3 (Parlist2 PARLIST2)
    #define Parlist1_size (0 PARLIST1)
    #define Parlist2_size (0 PARLIST2)
    #define Parlist3_size (0 PARLIST3)
    

  • This is *EXACTLY* what I've been searching for!
    I already arrived by myself to this solution with #define PARLIST macros, but I missed the final 8 lines, and I wasn't able to figure out how to proceed.
    I knew I will find a solution asking the KEIL forum and I thank all of you for your support.
    Ciao. Bruno