I'm using union to fill some message fields in a char type message buffer. If the length of the message is constant, it works correctly. See the simplified code sample below.
The problem is, my message can have variable length. Specifically, the const N will be decided on runtime. Is there a way to keep using unions by dynamically allocating memory for buf?
I'm exploring smart pointers but haven't had any luck so far.
const int N = 4;
struct repeating_group_t {
uint8_t field1;
uint8_t field2;
}rpt_group;
struct message_t
{
union
{
char buf[2 + 2*N];
struct {
uint8_t header;
uint8_t block_len;
std::array<repeating_group_t, N> group;
};
};
};
int main()
{
message_t msg;
msg.header = 0x32;
msg.block_len = 8;
for (auto i = 0; i < N; i++)
{
msg.group[i].field1 = i;
msg.group[i].field2 = 10*i;
}
// msg.buf is correctly filled
return 0;
}
As said in the comments, use std::vector.
int main() {
// before C++17 use char
std::vector<std::byte> v.
v.push_back(0x32);
v.push_back(8);
for (auto i = 0; i < N; i++) {
v.push_back(i);
const uint16_t a = 10 * i;
// store uint16_t in big endian
v.push_back(a >> 16);
v.push_back(a & 0xff);
}
}
For custom datatypes, you could provide your own stream-like or container-like container and overload operator>> or another custom function of your choice for your datatypes.
struct Message{
std::vector<std::byte> v;
Message& push8(uint8_t t) { ... }
// push 16 bits little endian
Message& push16le(uint16_t t) { ... }
// push 16 bits big endian
Message& push16be(uint16_t t) { ... }
// etc
Message& push(const Repeating_group& t) {
v.push_back(t.field1);
v.push_back(t.field2);
return v;
}
// etc.
};
int main(){
Message v;
v.push8(0x32).push8(8);
for (...) {
v.push(Repeating_group(i, i * 10));
}
}
You can't have N evaluated at runtime because both c-array (your buf) and std::array have size information in its type.
Also - using union for (de)serialization is not a good practice - size of your structure will depend on alignment needed on given machine it is compiled for and so on... You could add packed attribute to overcome it, but you still have plenty of platform dependency problems here.
Regarding variable length - you'd need to write custom (de)serializer that will understand and store/read that size information to recreate that container on the other end.
Where do you want to pass these messages?
Related
I have a struct that contains a const array, and would like to initialise it to specific values upon construction. Unfortunately, its contents depend on several parameters which are passed into the constructor as parameters, and require a function to compute the contents of the array.
What I'd ideally like to do looks something like this:
struct SomeType {
const unsigned int listOfValues[32];
unsigned int[32] processParameters(unsigned int parameter) {
unsigned int arrayValues[32];
for(int i = 0; i < 32; i++) {
arrayValues[i] = i * parameter;
}
return arrayValues;
}
SomeType(unsigned int parameter) : listOfValues(processParameters(parameter)) {
}
};
Of course there are several issues here (returning an array from a function is not possible, data type mismatches, etc). However, is there any way this is possible?
I've seen other similar questions suggest using a std::vector for this, but the heap allocation(s) this incurs is something my performance budget can't afford.
As Nathan suggested you should change the raw array with an std::array. This way you still have the benefit of stack allocation but now you can initialize from a copy.
using MyArray = std::array<unsigned int, 32>;
const MyArray listOfValues;
MyArray processParameters(unsigned int parameter) {
MyArray arrayValues;
for(int i = 0; i < 32; i++) {
arrayValues[i] = i * parameter;
}
return arrayValues;
}
I removed the const from the array data type since it's not necesary because your array is const already, also with const unsigned int you wouldn't be able to set the values of arrayValues at run time.
Does this serve your purpose? No heap allocations that I can see.
struct SomeType {
const unsigned int *listOfValues;
const unsigned int * processParameters(unsigned int parameter) {
for(int i = 0; i < 32; i++) {
_listOfValues[i] = i * parameter;
}
return _listOfValues;
}
SomeType(unsigned int parameter) :
listOfValues(processParameters(parameter))
{
}
private:
unsigned int _listOfValues[32];
};
Trying to understand the proper way to copy values into an class member array. Currently, I take each value of the array and copy them into the corresponding element of the member array:
struct IPAddress
{
IPAddress(const unsigned char values[4]) :
values{values[0], values[1], values[2], values[3]}
{
}
const unsigned char values[4];
};
int main(int argc, char** argv)
{
unsigned char values[] = {10, 0, 0, 1};
IPAddress address(values);
return 0;
}
This works, but is there a way to "automagically" copy all the values in the constructor? I mean, what would I do if the values were of a class had 100 elements instead of 4? Or 1000?
I'm aware that I should be using std::array. But since this code is built for a microcontroller, using std library is not really an option.
Any takers?
You should be using std::array. This is one part of the standard library that shouldn't be offensive to embedded programming.
If you don't have access to it, it's not hard to implement a class just like it. It's a straight forward aggregate with saner semantics than raw arrays. It's also likely to be reused, which makes it a good candidate for a utility you should implement.
Failing that, you can rely on delegating c'tors, which I only add here for the intellectual exercise:
struct IPAddress
{
IPAddress(const unsigned char values[4])
: IPAddress(values, std::make_index_sequence<4>{})
{
}
const unsigned char values[4];
private:
template<std::size_t... I>
IPAddress(const unsigned char values[4], std::index_sequence<I...>)
: values{values[I]...}
{
}
};
The key is in the pack expansion values{values[I]...}, which turns into an initializer not unlike your original one. See it live.
I'm aware that I should be using std::array. But since this code is built for a microcontroller, using std library is not really an option.
If you don't want to include array, you can still implement your own type for solving your issue:
template<typename T, std::size_t N>
class values_t {
public:
values_t(const T *ptr) {
// copy N elements
for (std::size_t i = 0; i < N; ++i)
value[i] = ptr[i]; // copy element
}
T& operator[](int i) { return value[i]; }
const T& operator[](int i) const { return value[i]; }
private:
typename std::remove_const<T>::type value[N];
};
Then, initializing the values data member of IPAddress becomes much simpler:
struct IPAddress
{
IPAddress(const unsigned char values[4]) :
values{values} {} // <-- copy as a whole
values_t<const unsigned char, 4> values;
};
Say for example that I have a class, that stores a very large array of some datatype (__type) as a pointer. However, I wish to initialize an object of this class using a different type. The code I have can be condensed to below:
template <typename __type> class MyStorageClass {
private:
__type* _data;
public:
template <typename __alt> MyStorageClass(int size, __alt* data) { // some init function }
extern friend print() const; // print to the screen
}
This works fine if I make an object of MyStorageClass<int> and initialize it to (new int[2] { 1, 2 }). However, the problem occours if I try to initialize it as: (new float[2] { 1, 2 }), even though the size of int and float are the same (so in theory they will cast to each other).
If I initialize it by: _data = (__type*) data;, the elements get changed.
MyStorageClass<int> msc1(2, new float[2] { 1, 2 });
msc1.print();
Yields: msc1=[1065353216, 1073741824], not msc1=[1, 2]
If I initialize it through a for loop:
// some init function
_data = new __type[size];
for (int i = 0; i < size; i++) _data[i] = data[i];
This works, and properly defines the object. However, It creates a new array in memory (at &_data) of the same size as sizeof(data), rather than use the already allocated memory at &data, which is unnecessarily memory intensive and can be confusing to the user.
QUESTION: Is there a way to cast an array (from float* to int* or another data type) using the same memory address?
UPDATE: Try with unions failed.
union FloatIntUnion{
float _f;
int _i;
FloatIntUnion(int i) { _i = i; }
FloatIntUnion(float f) { _f = f; }
operator float() { return _f; }
operator int() { return _i; }
operator std::string() const { std::stringstream oss; oss << _f; return oss.str(); }
};
MyStorageClass<int> msc2(2, new FloatIntUnion[2]{ float(1), float(2) });
msc2.print();
Yields: msc1=[1065353216, 1073741824]
Even if int(1) and float(1) has the same value, the bit patterns stored in memory are totally different.
When you do (int*) data; you tell the compiler that the bit patterns are the same, but as you see when you print them, they are not.
So this is not going to work.
In the loop in option 2), the assignment _data[i] = data[i]; doesn't just copy 4 bytes, it also transforms the bit patterns from float to int.
What I want to do: I need to store cell data in block-wise form, that is
*cell_member1[cell0] .. cell_member1[cellN] ... cell_memberM[cell0] .. cell_memberM[cellN]*
Then I need to access this data efficiently and, if possible, using a nice syntax. It would be great if I could define the data to be stored easily, i.e. by defining an object with members as the data that I want to store and passing it to some "magic" that does everything for me.
Motivation: why I need to do it this way? Cache trashing. In some inner loops only some members of the objects are accessed. Wasting half of a cache-line with unused memory is not an option for my application. I could store pointers in the objects that point to some sequential memory region. This wastes memory and forces me to use a different syntax in this regions.
How I'm currently doing it: I have a container of the form:
template<class T> struct Container {
char* data;
Container(const int n) {
data = new char[n*T::spaceRequirements()]; //< Data stored "block-wise"
new(data) typename T::Flags[n]; //< Flags stored "cell-wise"
}
/// Destructor ommited for briefness.
};
in which I store data for some cells of type T. I need some flags per cell and right now I'm using std::bitset to store them which means that I need to store this bitsets in cell-wise form:
*cell_member1[cell0] ... cell_memberM[cell0] ... cell_member1[cellN] .. cell_memberM[cellN]*
I am describing how much data per cell needs to be stored in the following class, which also provides access to the data:
template<int nd> struct CellAccessor {
/// Cell flags are stored cell-wise:
typedef std::bitset<64> Flags;
enum { DELETE = 0, ///< Cell marked for deletion
REFINE = 1 ///< Cell marked for refinement
//...
}; ///< Enum for the flags.
static inline Flags& flags(const int cellId) {
return *reinterpret_cast<Flags*>(data + sizeof(Flags)*cellId); }
template<int pId> static inline Flags::reference flags(const int cellId) {
return flags(cellId)[pId]; } //< Cell-wise access to the properties
/// The rest of the data is stored block-wise:
static inline int& order(const int cellId) { ///< One int field.
return *reinterpret_cast<int*>
(data + maxNoCells*sizeof(Flags) + sizeof(int)*cellId);}
/// Coordinate vector with nd components:
static inline double& coordinates(const int cellId, const int i) {
return *reinterpret_cast<double*>
(data + maxNoCells*(sizeof(Flags)+sizeof(int))
+ maxNoCells*i*sizeof(double) + sizeof(double)*cellId); }
template<int i> static inline double& coordinates(const int cellId) {
return *reinterpret_cast<double*>
(data +maxNoCells*(sizeof(Flags)+sizeof(int)+i*sizeof(double))
+ sizeof(double)*cellId); }
/// Total amount of memory to allocate per cell: (used by Container)
static inline int spaceRequirements() { return
sizeof(Flags) // Flags
+ sizeof(int) // order
+ nd*sizeof(double) // coordinates
;}
/// Constructor gets pointer to the beginning of the container
/// and the offset for the member variables:
CellAccessor(char* d, int n){data = d; maxNoCells = n;}
private:
static char* data; ///< Pointer to the beginning of the container.
static int maxNoCells; ///< Cell offset for the member variables.
};
template<int nd> char* CellAccessor<nd>::data = nullptr;
template<int nd> int CellAccessor<nd>::maxNoCells = 0;
And I use it like this:
int main() {
int maxNoCells = 10000; ///< Maximum number of cells (=cell offset).
typedef CellAccessor<2> A;
Container< A > cellData(maxNoCells); ///< Allocate cell data.
A cells(cellData.data,maxNoCells); ///< Provides access to cell data.
for(int i = 0; i < maxNoCells; ++i){
cells.flags<A::DELETE>(i) = i%2==0 ? true : false;
cells.flags<A::REFINE>(i) = i%2==0 ? false : true;
cells.coordinates(i,0) = i;
cells.coordinates<1>(i) = -((double)i);
cells.order(i) = 2;
}
}
Pros:
The data is in block-wise form, which is what I needed.
The syntax is ok.
Problems:
My classes are doing too much: providing access to the data for the users, providing how much data needs to be stored for the containers, providing how the data should be moved/copied/swaped for my data structures (which are trees...)...
I can't use STL algorithms without iterators. I've implemented iterators by making them store the cell index and reimplementing the CellAccessor class inside them (bad! DRY!).
Bitset is still being stored in cell-wise form. I could re-implement bitset for my block-wise data structure...
data and maxNoCells are static variables, but I could make them normal member variables if required.
Question: is there any efficient way to store "objects" (or what we conceptually understand by objects) in block-wise form and access them as if they were stored in a std container such as vector?
What you want is a style of a "COLUMN BASED" memory access
You can easily implement it using std::vector as your column type or create your own "column" type with your own underlying memory management - but std::vector should work just fine
Now once you have your column type you create your "TABLE" type.
In a way your table cab be just a vector of vectors. You can of course wrap it up in order to get better looking accessors (If you want to access by row (object) first and column (property) after.
This is I think the best general approach.
Even In your specific case - since you want to save memory using bit length flags, as mentioned by Bart van Ingen Schenau you can use a vector<bool> so the general approach stands
I would use parrallel arrays to meet the requirements:
template <int nd>
class CellAccessor {
public:
enum { DELETE = 0, ///< Cell marked for deletion
REFINE = 1, ///< Cell marked for refinement
//...
NUM_FLAGS
}; ///< Enum for the flags.
CellAccessor(int numCells) {
for (int i=0; i<NUM_FLAGS; i++) { m_flags[i] = new bool[numCells]; }
m_order = new int[numCells];
for (int i=0; i<nd; i++) { m_coordinates[i] = new double[numCells]; }
}
// Destructor, copy-constructor & assignment operator omitted for brevity
template<int F> inline bool& flags(const int cellId) {
return m_flags[F][cellId]; }
inline bool& flags(const int cellId, int flag) {
return m_flags[flag][cellId]; }
inline int& order(const int cellId) {
return m_order[cellId]; }
template<int i> inline double& coordinates(const int cellId) {
return m_coordinates[i][cellId]; }
inline double& coordinates(const int cellId, int i) {
return m_coordinates[i][cellId]; }
private:
bool* m_flags[NUM_FLAGS];
int* m_order;
double* m_coordinates[nd];
};
Not sure that understood correctly the question. It looks like you are trying to allocate data in a sequential array of bytes. Why?
but in any case you could do it simply by using arrays:
class Cell {
std::bitset<64> flags;
int order;
double coordinates[2];
}
int main() {
const int maxNoCells = 10000;
Cell cells[maxNoCells];
for(int i = 0; i < maxNoCells; i++) {
cells[i].flags = ...;
cells[i].coordinates[0] = i;
cells[i].coordinates[1] = -i;
cells[i].order=2;
}
}
and then cast it to (char *)cells if needed. Your classes will be allocated in a segmented fashion in a contiguous memory strip. You could use it for read/write/net. The only issue is that you have to take care of 32/64 bit alignments in particular if it is
shared between different architectures.
Here is another version which would be a bit better for caching if you insist on using different fields in separate loops:
template<int size>
class CellAccessor {
std::bitset<64> flags[size];
int order[size];
double coordinates[size][2];
public:
std::bitset<64> &getFlags(int id) {
return flags[id];
}
int &getOrder(int id) {
return order[id];
}
...
}
main() {
CellAccessor<10000> ca;
for(...i++) {
ca.getOrder(i) = 2;
ca.getCoordinates(i)[0] = i;
...
}
}
A few examples of what I'm referring to:
typedef struct SOME_STRUCT {
unsigned int x1;
unsigned int x2;
unsigned int x3;
unsigned int x4;
// What I expected would work, but doesn't; the 2nd parameter gets
// turned into an 8-bit quantity at some point within memset
SOME_STRUCT() { memset( this, 0xFEEDFACE, sizeof( *this ) ); }
// Something that worked, but seems hokey/hackish
SOME_STRUCT() {
unsigned int *me = (unsigned int *)this;
for( int ii = 0; ii < sizeof(*this)/sizeof(*me); ++ii ) {
me[ii] = 0xFEEDFACE;
}
}
// The far-more-verbose-but-C++-way-of-doing-it
// This works, but doesn't lend itself very well
// to being a drop-in way to pull this off on
// any struct.
SOME_STRUCT() : x1( 0xFEEDFACE )
, x2( 0XFEEDFACE )
, x3( 0XFEEDFACE )
, x4( 0XFEEDFACE ) {}
// This would work, but I figured there would be a standard
// function that would alleviate the need to do it myself
SOME_STRUCT() { my_memset( this, 0xFEEDFACE, sizeof(*this) ); }
}
I can't use valgrind here, and my options are limited as far as various debugging libraries I have access to -- which is why I'm doing it myself for this one-off case.
Here’s a partial example of using std::generate() safely:
#include <algorithm>
struct Wizard {
size_t i;
static unsigned char magic[4];
Wizard() : i(0) {}
unsigned char operator()() {
size_t j = i++;
i %= sizeof(magic); // Not strictly necessary due to wrapping.
return magic[j];
}
};
unsigned char Wizard::magic[4] = {0xDE,0xAD,0xBE,0xEF};
std::generate(reinterpret_cast<unsigned char*>(this),
reinterpret_cast<unsigned char*>(this) + sizeof(*this),
Wizard());
(Of course, the endianness may or may not be right, depending on how you’re looking and what you’re expecting to see when you do!)
I would declare this constructor:
SOME_STRUCT( unsigned int magic) : x1 (magic), x2 (magic), x3 (magic), x4 (magic) {}
This is very similar to your third option, and seems to be the natural C++ way of doing it.
A point not made by others is this:
I think it is unsafe to do this for Non-POD types. Ironically, adding the initialization into a constructor makes it non-pod. Therefore I propose a freestanding function that checks for POD-ness statically (sample uses c++0x type_traits but you could use Boost as well)
#include <iostream>
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_pod<T>::value>::type* FeedFace(T& v)
{
static const unsigned char MAGIC[] = { 0xFE, 0xED, 0xFA, 0xCE };
unsigned char *me = reinterpret_cast<unsigned char *>(&v);
for( size_t ii = 0; ii < sizeof(T)/sizeof(unsigned char); ++ii )
me[ii] = MAGIC[ii % sizeof(MAGIC)/sizeof(unsigned char)];
}
struct Pod { char data[37]; };
struct NonPod : Pod { virtual ~NonPod() { } };
int main()
{
Pod pod;
FeedFace(pod);
NonPod nonpod;
// FeedFace(nonpod); // fails to compile (no matching function call)
return 0;
}
I assume this allows for nasty hacky stuff, like this:
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
int main(void)
{
struct SOME_STRUCT {
unsigned int x1;
unsigned int x2;
unsigned int x3;
unsigned int x4;
} foo;
fill(reinterpret_cast<unsigned int *>(&foo),
reinterpret_cast<unsigned int *>(&foo) + sizeof(foo) / sizeof(unsigned int),
(unsigned int)0xDEADBEEF);
cout << foo.x1 << endl;
cout << foo.x2 << endl;
cout << foo.x3 << endl;
cout << foo.x4 << endl;
return (0);
}
Basically abusing std::fill() with pointer casts.
You could reinterpret_cast this as a char* and then use std::generate with a predicate that rotates through the values you care about. If I get time later I'll try to sketch the code.
Also have you considered for example an LD_PRELOAD memory checking malloc library?
Here's another hacky method.
SOME_STRUCT() {
x1 = 0xFEEDFACE;
memmove(&(this->x2), this, sizeof(*this)-sizeof(x1));
}
Even if your memset() attempt did work, it makes an assumption about the structure packing and is therefore not guaranteed to be correct. There is no programmatic way to iterate through the members of a struct and assign them in C or C++. You will therefore need to be content with assigning the members individually. Having said that, if you feel that you are comfortable with the memory layout of the structure and don't need to worry about portable code, you can just as easily initialize it with a for loop.
unsigned int i, *ar = (unsigned int *)&my_struct;
for (i = 0; i < sizeof(my_struct) / sizeof(unsigned int); i++) {
ar[i] = 0xdeadbeef;
}