Reputation: 35
I know the best solution would be to just use standard C or even better C++, but unfortunately I can't cause I have to use a function which I can't change and it requires the data to be in this format.
The struct tComplex_R AmpLinRx[1];
is using something called "struct hack" and I can't change this.
Therefore I can't change the 2 structs and the format of the data, which have to be a pointer of tOutputVRx_R
.
I have the following 2 structs:
typedef struct tComplex_R {
float real;
float imag;
}tComplex_R;
typedef struct tOutputVRx_R {
float range;
float vel;
tComplex_R AmpLinRx[1];
} tOutputVRx_R;
Now I want to have the struct tOutputVRx_R
with length 3 and in there the struct tComplex_R
with length 32.
Like output_vrx[3].AmplLinRx[32]
int n_antennas = 32;
int n_max_detections = 3;
size_t n_out_vrx = n_max_detections * (sizeof(tOutputVRx_R) + n_antennas * sizeof(struct tComplex_R);
tOutputVRx_R* output_vrx = (tOutputVRx_R*)malloc(n_out_vrx);
output_vrx
have to be a pointer, no pointer pointer (I found a solution for that but can't use it with the existing code) and I can't change the 2 structs.
Later I fill it with Data like this, where a is an array with numbers from 0-31:
for(int j = 0; j < n_antennas; j++){
output_vrx_device_temp[0].AmpLinRx[j].real = a[j];
output_vrx_device_temp[0].AmpLinRx[j].imag = b[j];
}
output_vrx_device_temp[0].range = 8;
output_vrx_device_temp[0].vel = 5;
for(int j = 0; j < n_antennas; j++){
output_vrx_device_temp[1].AmpLinRx[j].real = c[j];
output_vrx_device_temp[1].AmpLinRx[j].imag = d[j];
}
Now I acces the data with a simple printf:
for(int i = 0; i < 32; i++){
printf("Real: %e, Imag: %e \n", output_vrx_device_temp[0].AmpLinRx[i].real, output_vrx_device_temp[0].AmpLinRx[i].imag);
}
But the Data is not the same as I specified in the variables a, b, c or d. The output looks like:
Real: 0.000000e+00, Imag: 0.000000e+00
Real: 8.000000e+00, Imag: 5.000000e+00
Real: 0.000000e+00, Imag: 0.000000e+00
Real: 8.000000e+00, Imag: 5.000000e+00
Real: 0.000000e+00, Imag: 0.000000e+00
Real: 1.000000e+00, Imag: 1.000000e+00
Real: 2.000000e+00, Imag: 2.000000e+00
Real: 3.000000e+00, Imag: 3.000000e+00
Real: 4.000000e+00, Imag: 4.000000e+00
Real: 5.000000e+00, Imag: 5.000000e+00
Real: 6.000000e+00, Imag: 6.000000e+00
Anybody know how to solve this?
Upvotes: 2
Views: 76
Reputation: 223699
Disclaimer: This is a hack, and is not guaranteed to work in all cases, however it should work in practice. Alignment also shouldn't be an issue in this particular case given that all members have the same alignment.
Indexing output_vrx_device_temp
won't work as since pointer arithmetic will be done in increments of sizeof(tOutputVRx_R)
instead of that plus the size of the 31 instances of tComplex_R
. So you need to do the pointer arithmetic manually on a converted pointer.
We can first create a function that can index into the array:
// a: start of "array" with struct hack / flexible member
// i: index of array element
// n: the size of the flexible member
tOutputVRx_R *idx(tOutputVRx_R *a, int i, int n)
{
// use an unsigned char * to perform single byte pointer arithmetic.
unsigned char *p = (unsigned char *)a;
// get the size of the flexible member, subtracting 1 since it's part of the parent struct
int fa_size = sizeof(tComplex_R) * (n-1);
// calculate the offset
int offset = i * (sizeof(tOutputVRx_R) + fa_size);
// offset the char array and cast back
return (tOutputVRx_R *)(p + offset);
}
Then we can modify the original code to use this function instead of indexing output_vrx_device_temp
:
for(int j = 0; j < n_antennas; j++){
idx(output_vrx_device_temp,0,n_antennas)->AmpLinRx[j].real = a[j];
idx(output_vrx_device_temp,0,n_antennas)->AmpLinRx[j].imag = b[j];
}
idx(output_vrx_device_temp,0,n_antennas)->range = 8;
idx(output_vrx_device_temp,0,n_antennas)->vel = 5;
for(int j = 0; j < n_antennas; j++){
idx(output_vrx_device_temp,1,n_antennas)->AmpLinRx[j].real = c[j];
idx(output_vrx_device_temp,1,n_antennas)->AmpLinRx[j].imag = d[j];
}
for(int i = 0; i < n_antennas; i++){
printf("Real: %e, Imag: %e \n", idx(output_vrx_device_temp,0,n_antennas)->AmpLinRx[i].real,
idx(output_vrx_device_temp,0,n_antennas)->AmpLinRx[i].imag);
}
for(int i = 0; i < n_antennas; i++){
printf("Real: %e, Imag: %e \n", idx(output_vrx_device_temp,1,n_antennas)->AmpLinRx[i].real,
idx(output_vrx_device_temp,1,n_antennas)->AmpLinRx[i].imag);
}
Note that we're still indexing past the end of an array of size 1 for the AmpLinRx
member, although it probably shouldn't be an issue given that the memory it's extending into is dynamically allocated and not being accessed in any other way.
Upvotes: 1