Please give me the answer. Thanks
struct ZMessage {
uint8_t id[sizeof(struct ZID)];
struct ZBlock block[1]; //what different 'ZBlock block'
};
Please give me the answer. Thanks
struct ZMessage {
uint8_t id[sizeof(struct ZID)];
struct ZBlock block[1]; //what different 'ZBlock block'
};
C and C++ are different languages.
struct ZBlock block[1];
is a C syntax.
In classic C a name of struct
is ... not a type. It's a name of block (of variables). C got concept of anonymous struct. Anonymous structs allowed to create separate block of variables or fields with proper alignment, i.e following Test
would have field b
started from a new word, i.e. size of block will be 4 if size of short
is 2.
// this is correct ONLY in C
int main(void)
{
struct Test {
short a : 5;
struct {
short b : 5;
short c : 6;
};
};
// you can have a name of variable matching a name of block.
// regardless of name, declaration without struct is forbidden
struct Test Test;
Test.b = 3;
printf("Test.b equals to %d, size of test %d", Test.b, sizeof(Test));
// Output: Test.b equals to 3, size of test 4
return EXIT_SUCCESS;
}
Therefore in any context where you declare a variable or function parameter you have to precede struct-id by keyword struct
to create a type-id.
In C++ struct
is a class-type. It's name can be used as type-id, so you don't need a keyword struct
. C++ doesn't allow anonymous structs but allows anonymous unions and anonymous namespace.
In fact that you declare ZMessage
without a typedef
suggest that it is C++ context or a recent C version. C syntax is supported for backward compatibility of header files.
About array of size 1. In that case expression consisting out of name block
is a pointer to array of ZBlock
. Using size 1 to declare a flexible array according to C standard is no longer correct.
C had a special rule that you can use pointer arithmetics (and operator[] as extent of that) to access implicitly allocated memory after this struct, if array is the last member of struct and got incomplete type.
In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply
Creation of such might look like this:
// might have size 4 or size 8 - greater than sizeof(short)
struct Test {
short size;
short data[]; // Incomplete array type - C11.
// `short data[1]; is NO longer a flexible array.
};
int count = 10;
// note: C doesn't support Test::data construct
// C++ would require a type cast (Test*)
struct Test* pack = malloc(sizeof(struct Test) + count*sizeof(short));
pack->size = count;
pack->data[0] = 4;
pack->data[1] = 8;
...
Here is a problem with padding. We most likely allocate more memory than we need. correct way is to determine offset of address beyond last element of data[]. In C, while sizeof(Test) can be, e.g. 8, offset of data[0] can be still 2.
// such usage of offsetof is undefined in C++
struct Test* pack = malloc(offsetof(struct Test, data[count]));
C++ explicitly doesn't allow to go beyond boundary of object, i.e. beyond boundary of struct. But some compilers support it as extension, usually with no array size declared in that case or with size 1 in case of some compilers. Caveat with those is that it's not consistent if compiler assumes struct to include first member of single array or array can have a zero length.