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);
}