Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lookup table index for struct array

Tags:

c

I'm reading a binary file where one of the bytes defines a type of data.

Typically:

0x13 => FOO
0x14 => BAR

But, as it is, there can be multiple definitions of same type, then real type is defined elsewhere, but it is not always accessible. Therefore I would like to print all possibilities if no sub specification is defined.

E.g.:

0x13 => FOO
0x14 => BAR
0x14 => BAZ <-- also "type" 0x14
0x15 => XEN

To store the type definitions and descriptions I have a struct in the format of:

struct data_def {
    char id;
    char *name;
    char *desc;
    ...
};

If it was possible I would have had an array as in:

static const struct data_def data_db[][] = {

    ...
    } /* index 0x13 */
        {0x13, "FOO", "This is foo", ...}
    }, /* index 0x14 */
        {0x14, "BAR", "This is bar", ...},
        {0x14, "BAZ", "This is baz", ...}
    }, /* index 0x15 */
        {0x15, "XEN", "This is xen", ...}
    }
}

In order so that data_db[0x14][1].name == BAZ, etc.

But AFAIK this is not possible. Or is it? (C89).


I am looking for another way to do it. Was thinking of something like this:

static const struct data_def data_db[] = {
    ...
    {0x13, "FOO", "This is foo", ...},
    {0x14, "BAR", "This is bar", ...},
    {0x14, "BAZ", "This is baz", ...},
    {0x15, "XEN", "This is xen", ...}
}

And then have a lookup table as in where each first entry starts. This could off course also be dynamically created by looping data_db, but would rather have it statically defined (I think – I haven't decided):

static const char data_index[] {
    ...
    0x20, /* at index 0x13 of data_index */
    0x21, /* at index 0x14 of data_index */
    0x23, /* at index 0x15 of data_index */
}

Giving that one could print, (or other), by doing e.g.:

while (data_db[data_index[0x14 + i]].id == 0x14) {
         print data_db[data_index[0x14 + i]].name
         ++i
}

Is there a better way to solve this? I imagine this is something that has been done a billion times before with similar scenarios. I would rather not use any libraries outside of the standard library as this eventually is only a small part of the program and the rest of the code is "free" of that as well.

like image 794
Zimzalabim Avatar asked Sep 26 '26 23:09

Zimzalabim


1 Answers

This is just a shot in the dark, but if the number of types within an identifier group has an upper bound and if you can utilize a value that you know will not be one of your types, you could do something like this:

#define MAX_NUM_TYPES    3
#define INVALID_TYPE     0xff

struct Data_Def{
    unsigned char id;
    char * name;
    char * desc;
};

static const struct Data_Def data_db[][MAX_NUM_TYPES] = {
 .
 .
 .

    {    /* Index 0x13  */
         /*  id           name      desc            */
        {    0x13,        "FOO",    "This is foo"    },
        {    0x13,        "BAR",    "This is bar"    },
        {    INVALID_TYPE, NULL,    NULL             },
    },
    {    /* Index 0x14  */
         /*  id           name      desc            */
        {    0x14,        "BAZ",    "This is baz"    },
        {    INVALID_TYPE, NULL,    NULL             },
        {    INVALID_TYPE, NULL,    NULL             },
    },
};

And if you want to print...

unsigned char index = 0;
/* Print all types within a group with id 0x13. */
while ((data_db[0x13][index].id != INVALID_TYPE) && (index < MAX_NUM_TYPES))
{
    printf("%s", data_db[0x13][index].name);
    index++;
}

This may not work at all for what you're trying to accomplish and depending on the number of types per group, it may be a complete waste of code space. However, it is one way of attacking the problem.

Hope this helps!

like image 70
embedded_guy Avatar answered Sep 29 '26 22:09

embedded_guy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!