I am trying to figure out whether there is a workaround in C to have a flexible array member in a struct(s), that is not the last one. For example, this yields compilation error:
typedef struct __attribute__((__packed__))
{
uint8_t slaveAddr; /*!< The slave address byte */
uint8_t data[]; /*!< Modbus frame data (Flexible Array
Member) */
uint16_t crc; /*!< Error check value */
} rtuHead_t;
This does not yield an error:
typedef struct __attribute__((__packed__))
{
uint8_t slaveAddr; /*!< The slave address byte */
uint8_t data[]; /*!< Modbus frame data (Flexible Array
Member) */
} rtuHead_t;
typedef struct __attribute__((__packed__))
{
rtuHead_t head; /*!< RTU Slave addr + data */
uint16_t crc; /*!< Error check value */
} rtu_t;
But does not work. If I have an array of bytes: data[6] = {1, 2, 3, 4, 5, 6}; and cast it to rtu_t, then crc member will equal 0x0302, not 0x0605.
Is there any way to use the flexible array members in the middle of the struct (or struct in a struct)?
It cannot be done in ISO C. But...
The GCC has an extension allowing Variably Modified types defined within the structures. So you can define something like this:
#include <stddef.h>
#include <stdio.h>
int main() {
int n = 8, m = 20;
struct A {
int a;
char data1[n];
int b;
float data2[m];
int c;
} p;
printf("offset(a) = %zi\n", offsetof(struct A, a));
printf("offset(data1) = %zi\n", offsetof(struct A, data1));
printf("offset(b) = %zi\n", offsetof(struct A, b));
printf("offset(data2) = %zi\n", offsetof(struct A, data2));
printf("offset(c) = %zi\n", offsetof(struct A, c));
return 0;
}
Except a few warnings about using non-ISO features it compiles fine and produces expected output.
offset(a) = 0
offset(data1) = 4
offset(b) = 12
offset(data2) = 16
offset(c) = 96
The issue is that this type can only be defined at block scope thus it cannot be used to pass parameters to other functions.
However, it could be passed to a nested function, which is yet-another GCC extensions. Example:
int main() {
... same as above
// nested function
int fun(struct A *a) {
return a->c;
}
return fun(&p);
}
A flexible array member must be the last member of the struct, and a struct containing a flexible array member may not be a member of an array or another struct.
The intended use of such a struct is to allocate it dynamically, putting aside enough space for the other members plus 0 or more elements of the flexible member.
What you're attempting to do is overlay a struct onto a memory buffer that contains packet data that you want to parse simply by accessing the members. That's not possible in this case, and in general doing so is not a good idea due to alignment and padding issues.
The proper way to do what you want is to write a function that deserializes the packet one field at a time and places the result in a user-defined structure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With