user2475269
user2475269

Reputation:

Initializing a const array inside a struct

#define LENGTH 6
typedef char data_t[LENGTH];
struct foo {
    const data_t data;
    ...
}
...
void bar(data_t data) {
    printf("%.6s\n", data);
    struct foo myfoo = {*data};
    printf("%.6s\n", foo.data);
}

I'm trying to have this struct which holds directly the data I'm interested in, sizeof(foo) == 6+the rest, not sizeof(foo) == sizeof(void*)+the rest. However I can't find a way to initialize a struct of type foo with a data_t. I think maybe I could remove the const modifier from the field and use memcpy but I like the extra safety and clarity.

I don't get any compile errors but when I run the code I get

123456
1??

so the copy didn't work properly I think.

This is for an arduino (or similar device) so I'm trying to keep it to very portable code.

Is it just not possible ?

EDIT: removing the const modifier on the data_t field doesn't seem to help.

Upvotes: 10

Views: 3525

Answers (2)

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

It is possible to do this, for some cost >=0.

typedef struct
{
    char c[LENGTH];
} data_t; // this struct is freely copyable

struct foo
{
    const data_t data; // but this data member is not
    int what;
};

void foo (char* x) {
    data_t d;                         // declare freely copyable struct instance
    memcpy(d.c, x, sizeof(d.c));      // memcpy it
    struct foo foo = { d, 42 };       // initialise struct instance with const member
    ...
};

Some compilers (e.g. clang) are even able to optimise away the redundant copying (from x to d.c and then from d to foo.data ⇒ from x straight to foo.data). Others (gcc I'm looking at you) don't seem to be able to achieve this.

If you pass around pointers to data_t rather than straight char pointers, you won't need this additional memcpy step. OTOH in order to access the char array inside foo you need another level of member access (.data.c instead of just .data; this has no runtime cost though).

Upvotes: 1

Petr Skocik
Petr Skocik

Reputation: 60068

It's impossible to do it in a standard compliant way.

Due to its being const, const char data[6]; must be initialized to be usable, and it may only be initialized statically (static objects with no initializer get automatically zeroed), with a string literal, or with a brace-enclosed initializer list. You cannot initialize it with a pointer or another array.

If I were you, I would get rid of the const, document that .data shouldn't be changed post-initialization, and then use memcpy to initialize it.

(const on struct members doesn't work very well in my opinion. It effectively prevents you from being able to have initializer functions, and while C++ gets around the problem a little bit by having special language support for its constructor functions, the problem still remains if the const members are arrays).

Upvotes: 1

Related Questions