Constant pointer to constant stuct

Hi,

I'm trying to create a data structure that contains something analogous to nested tables.

In my program I want to create a message structure that contains information about a message and then link to this message information on each field within the message. I was thinking of doing this using an array of structs within my message struct (see below). I also thought it would be better to have a pointer to the array of message fields as this means the array could be of variable length and declared constant elsewhere (saving resources).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct message
{
    const uint32_t message_id;
    const int32_t number_of_fields;
    const message_field* const fields;
};

struct message_field
{
    const int32_t start_index;
    const int32_t size;
};

const message_field msg1_fields[2] = {{1,2},{3,1}};
const message_field msg2_fields[1] = {1,4};

const message test_messages[2] = 
{{1,2, msg1_fields[0]},{2,2, msg2_fields[0]}};

I am however having issues with the syntax and accessing the subfields and was hoping someone could point out where I'm going wrong. As I understand it I've created a constant pointer to a constant message field structure within my message structure.
Last edited on
If you want to do this in "C style", then consider using a flexible array member:
https://en.wikipedia.org/wiki/Flexible_array_member

This way, you have all the data of a message in a single contiguous block of memory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
typedef struct
{
    int foo;
    /*whatever needs to be in each field*/
}
message_field;

typedef struct
{
    uint32_t message_id;
    size_t num_fields;
    message_field fields[]; // the flexible array member must be last
}
message;

message *alloc_message(const size_t num_fields)
{
    const size_t size = sizeof(message) + (num_fields * sizeof(message_field));
    message *msg = (message*)malloc(size);
    if (msg)
    {
        memset(msg, 0, size);
        msg->num_fields = num_fields;
    }
    return msg;
}

void do_something_with_message(const message *const msg)
{
    for (size_t i = 0; i < msg->num_fields; ++i)
    {
        printf("%d\n", msg->fields[i].foo);
    }
}

int main()
{
    message *msg = alloc_message(42);
    if (msg)
    {
        msg->fields[7].foo = 13;
        do_something_with_message(msg);
        free(msg);
    }
}


________

If you want to go with a more C++-like solution, consider converting message into a class and use an STL container, for example std::vector, as a member variable to store a variable number of the fields.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class message
{
public:
    message(const size_t num_fields) : fields(num_fields) { }

    size_t get_size(void) const
    {
        return fields.size();
    }

    const message_field &get_field(const size_t idx) const
    {
        return fields[idx];
    }

private:
    uint32_t message_id;
    std::vector<message_field> fields;
}
Last edited on
For struct members, only make those const when the initialisation value isn't going to change.

1
2
3
4
5
6
struct message
{
    const uint32_t message_id;
    const int32_t number_of_fields;
    const message_field* const fields;
};


Here message_id, number_of fields etc are const but not initialised - so they will contain an unknown value which can't be changed!

Also if you have a const that contains a constant value that doesn't change (ie a const number) between instantiations then consider making them static.
Topic archived. No new replies allowed.