Reputation:
#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
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
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