Specification:
Given: NxN Rmatrix.
Given: N, where N is 2 or 4.
Rmatrix
and N
.Set
function copies the information into a class data member(s) for later use when calling the API.print
function using the stored class data members, Rmatrix
, and N
.Rmatrix
, and N
.// ***** THE 3RD PARTY API **** (cannot be changed)
void compute(const creal32_T R_data[], const int R_size[2],
int* returnCode, int* stuff);
// **returnCode** and **stuff** are outputs.
Below is my attempt, but I get mostly 0's. Here is the code that I was able to run after many build errors.
NOTICE that the API refers to creal32_T R_data[]
whereas the test data refers to creal32_T R_data[4][4];
Two similar but different types were causing me to have build errors.
Array_3rd_Party_Inputs.hpp:
This part is just the test data from the third party for our unit test
I don't think I should include this section in my class wrapper around the 3rd party API (but if it is the only way to accomplish the goals, then I'll try to get a waiver).
#ifndef ARRAY_3RD_PARTY_INPUTS_HPP
#define ARRAY_3RD_PARTY_INPUTS_HPP
// This header file (and its data) comes from a 3rd party.
// NOTE: **** 3rd party is column-major ****
typedef int int32_T;
typedef struct
{
float re;
float im;
} creal32_T;
// The following struct provides input/output test data for unit tests.
// Shown are the inputs. Not shown are the outputs.
typedef struct Input_output_data_type
{
struct Inputs
{
int rc;
creal32_T R_data[4][4];
int32_T R_size[2];
} inputs;
} INPUT_OUTPUT_DATA_TYPE;
INPUT_OUTPUT_DATA_TYPE inputOutputData[2] =
{
{
{ // 2x2
0,
{
{ {111.0, 111.1}, {222.0, 222.2} }, // Col 1 -other two values in this row are {0+ 0i}
{ {333.0, 333.3}, {444.0, 444.4} } // Col 2
},
{
2, // R_size[0]
2 // R_size[1]
},
}
},
{
{ // 4x4
0,
{
{ {11.0, 11.1}, {12.0, 12.2}, {13.0, 13.3}, {14.0, 14.4} }, // Col 1
{ {21.0, 21.1}, {22.0, 22.2}, {23.0, 23.3}, {24.0, 24.4} }, // Col 2
{ {31.0, 31.1}, {32.0, 32.2}, {33.0, 33.3}, {34.0, 34.4} }, // Col 3
{ {41.0, 41.1}, {42.0, 42.2}, {43.0, 43.3}, {44.0, 44.4} }, // Col 4
},
{
4, // R_size[0]
4 // R_size[1]
},
}
}
};
#endif // ARRAY_3RD_PARTY_INPUTS_HPP
Set2DArray.cpp:
#include "Array_3rd_Party_Inputs.hpp"
#include <iostream>
template<int N, typename T>
static void
PrintRMatrixInput(T& R)
{
std::cout << "PrintRMatrixInput: N = " << N << "; T is type: " << typeid(T).name() << std::endl;
for (int rr = 0; rr < N; ++rr)
{
for (int cc = 0; cc < N; ++cc)
{
std::cout << R[cc][rr].re << " + " << (R[cc][rr].im) << "i\t";
}
std::cout << "\n";
}
std::cout << "\n\n";
}
struct ResultsXcorrMatrix // I created this struc to handle 2x2 and 4x4 matrix.
{
union
{
creal32_T RMatrixData[16]{};
creal32_T RMatrixData2[2][2];
creal32_T RMatrixData4[4][4];
};
};
class Matrix_Display_Class
{
public:
Matrix_Display_Class() {} // ctor
void SetRmatrix(creal32_T* rMatrix, int32_T rMatrixSize[2])
{
inR_.rMatrix_.RMatrixData = rMatrix;
inR_.rMatrixSize_ = rMatrixSize;
}
struct InputXcorrMatrix
{
union
{
creal32_T* RMatrixData{}; // maybe: "creal32_T RMatrixData[16]{}"
creal32_T RMatrixData2[2][2];
creal32_T RMatrixData4[4][4];
} rMatrix_{};
int32_T* rMatrixSize_{};
} inR_{};
};
int main()
{
// ResultsXcorrMatrix res{};
Matrix_Display_Class myDisp{};
// ******** print out 2x2 Array **********
INPUT_OUTPUT_DATA_TYPE* ioDataPtr = &inputOutputData[0];
INPUT_OUTPUT_DATA_TYPE::Inputs ioDataInputs = ioDataPtr->inputs;
std::cout << "\nEXPECTED THIS:" << std::endl;
PrintRMatrixInput<2>(ioDataInputs.R_data);
myDisp.SetRmatrix(ioDataInputs.R_data[0], ioDataInputs.R_size);
std::cout << "BUT GOT THIS:" << std::endl;
PrintRMatrixInput<2>(myDisp.inR_.rMatrix_.RMatrixData2);
// ******** print out 4x4 Array **********
ioDataPtr = &inputOutputData[1];
ioDataInputs = ioDataPtr->inputs;
std::cout << "EXPECTED THIS:" << std::endl;
PrintRMatrixInput<4>(ioDataInputs.R_data);
std::cout << "BUT GOT THIS:" << std::endl;
PrintRMatrixInput<4>(myDisp.inR_.rMatrix_.RMatrixData4);
} // END main
I tried examining memory addresses in VSCode, but got a confused. In the original program having this code, I stepped into SetRmatrix()
and saw that inR_.rMatrix_.RMatrixData
had the first struct members (i.e., .re
and .im
) fields set correctly. I thought that since RMatrixData2
should have the same address, then it would also have the correct values.
I tried different calling sequences such as using creal32_T rMatrix[4][4]
, but all my approaches led to compiler errors.
I tried a memcpy, but I did not like the ensuing segfault.
OUTPUT:
EXPECTED THIS:
PrintRMatrixInput: N = 2; T is type: A4_A4_9creal32_T
111 + 111.1i 333 + 333.3i
222 + 222.2i 444 + 444.4i
BUT GOT THIS:
PrintRMatrixInput: N = 2; T is type: A2_A2_9creal32_T
2.58476e-26 + 2.84464e-43i 0 + 0i
0 + 0i 0 + 0i
EXPECTED THIS:
PrintRMatrixInput: N = 4; T is type: A4_A4_9creal32_T
11 + 11.1i 21 + 21.1i 31 + 31.1i 41 + 41.1i
12 + 12.2i 22 + 22.2i 32 + 32.2i 42 + 42.2i
13 + 13.3i 23 + 23.3i 33 + 33.3i 43 + 43.3i
14 + 14.4i 24 + 24.4i 34 + 34.4i 44 + 44.4i
BUT GOT THIS:
PrintRMatrixInput: N = 4; T is type: A4_A4_9creal32_T
2.58476e-26 + 2.84464e-43i 0 + 0i 0 + 0i 0 + 0i
0 + 0i 0 + 0i 0 + 0i 0 + 0i
0 + 0i 0 + 0i 0 + 0i 0 + 0i
0 + 0i 0 + 0i 0 + 0i 0 + 0i
Your direct issue is that in your setter you make RMatrixData
an active member of an union:
inR_.rMatrix_.RMatrixData = rMatrix;
and the you attempt to do a type punning here (access to inactive member), which is undefined behavior.
PrintRMatrixInput<2>(myDisp.inR_.rMatrix_.RMatrixData2);
Also your ioDataInputs.R_data[0]
points to the first row of data
{{111.0, 111.1}, {222.0, 222.2}, {0,0}, {0,0}},
so it would be wrong anyway.
Then, your underlying issue is that you are trying to use some weird C-style coding with C++. Get rid of all of your raw arrays T arr[x][y]
and raw pointers, you can use std::array<T, N>
instead (array of array is also an option). If you need complex numbers, just use std::complex
. If you need a variant (I don't think you do), use std::variant
, in general I don't see any reason to have unions in your code.