Well, this code is not C because __attribute__((packed))
is only valid in gcc and some other specific implementation but definitely does not exist in standard C.
But provided sizeof(struct message) <= 10
, the rest of the code is correct code according to 4. Conformance
but contains unspecied behaviour and may contain undefined behaviour depending of the implementation
request(&devices[0]);
and void request(struct message *msg) {...}
: Ok: request
expects a struct message *
and receive the address of first element of an array of struct message
- all is fine here
struct request *req = (struct request *)&msg->data;
: that is the most interesting part.
msg->data
is a char array, that is an aggregate. The address of an aggregate is the address of its first byte. Said differently (char *) &msg-> data
(address of first byte of the aggregate) is the same as msg->data
(array decaying to a pointer to its first element)
(struct request *)&msg->data;
the pointer to char is casted to a pointer to struct request
. Depending of the implementation, nothing guarantees that the pointer will be correctly aligned. If it is not, this is undefined behaviour according to 6.3.2.3 Pointers § 7. If is is, we still have unspecified behaviour according to 6.5 Expressions § 6-7, because the new pointer will be used to store an element that has not the declared type of char[10]
. But this will be accepted by all known implementation, because internally they process the same char arrays (explicit type) and allocated memory (no declared type) - simply because they need to implement malloc
(see Is it possible to write a conformant implementation of malloc in C?)
The rest of the code contains no other problem. But it should be noticed that if the __attribute__(packed)
is honoured by the implementation, the field data
will be the third byte of the struct, which gives a weird alignment. That can lead to crashes on implementation that require strict alignment for certain types.
References from n1256 draft for C99
- Conformance
...
2 If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint is violated, the
behavior is undefined...
3 A program that is correct in all other aspects, operating on correct data, containing
unspecified behavior shall be a correct program...
6.3.2.3 Pointers
...
7 A pointer to an object or incomplete type may be converted to a pointer to a different
object or incomplete type. If the resulting pointer is not correctly aligned for the
pointed-to type, the behavior is undefined. Otherwise, when converted back again, the
result shall compare equal to the original pointer. When a pointer to an object is
converted to a pointer to a character type, the result points to the lowest addressed byte of
the object.
6.5 Expressions
...
6 The effective type of an object for an access to its stored value is the declared type of the
object, if any. If a value is stored into an object having no declared type through an
lvalue having a type that is not a character type, then the type of the lvalue becomes the
effective type of the object for that access and for subsequent accesses that do not modify
the stored value. If a value is copied into an object having no declared type using
memcpy or memmove, or is copied as an array of character type, then the effective type
of the modified object for that access and for subsequent accesses that do not modify the
value is the effective type of the object from which the value is copied, if it has one. For
all other accesses to an object having no declared type, the effective type of the object is
simply the type of the lvalue used for the access.
7 An object shall have its stored value accessed only by an lvalue expression that has one of
the following types:
- atype compatible with the effective type of the object,
- aqualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the
object,
- a type that is the signed or unsigned type corresponding to a qualified version of the
effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its
members (including, recursively, a member of a subaggregate or contained union), or
- a character type.