More elegant way to add object arrays to a longer array?

I'm using a union so I can break my ints and floats into bytes so they can be saved to an eeprom by a microcontroller. There are 12 "banks" each having 12 objects. (the code below is abbreviated hopefully avoid distractions.)
I have a something working, but I'd like to do something less ugly and more reusable and scalable.

I thought an array of pointers might work. I've used typedef to create an array of pointers to functions and member functions, but I'm not really sure how to do this with object arrays. I'm not even sure that would be any less ugly.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  union BankParam {    
    int inum;
    float fnum;
    char byte_param[4];
};

int main(){
	BankParam bits[12];
	BankParam ratio[12];
	BankParam period[12];
	
        int bank_num = 0;

	bits[bank_num].inum = 10;
	ratio[bank_num].fnum = .5f;
	period[bank_num].inum = 123;
	
        char array[48]
		
	for (int i = 0; i < 4; i++) {
		array[i] = bits[bank_num].byte_param[i];
		array[i+4] = ratio[bank_num].byte_param[i];
		array[i+8] = period[bank_num].byte_param[i];
	}
	
	// ... some code to write array to eeprom
}


Thanks for any help.
Last edited on
Like this, maybe?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Buffer{
    std::vector<std::uint8_t> data;
public:
    Buffer(size_t capacity = 0){
        if (capacity)
            this->data.reserve(capacity);
    }
    void add_int(int n){
        auto i = this->data.size();
        this->data.resize(i + sizeof(n));
        memcpy(&this->data[i], &n, sizeof(n));
    }
    void add_float(float x){
        auto i = this->data.size();
        this->data.resize(i + sizeof(x));
        memcpy(&this->data[i], &x, sizeof(x));
    }
    void send_to_eeprom() const{
        if (!this->data.size()){
            std::uint8_t dummy;
            ::send_to_eeprom(&dummy, 0);
        }
        ::send_to_eeprom(&this->data[0], this->data.size());
    }
};

Buffer buffer(48);
buffer.add_int(10);
buffer.add_float(.5f);
buffer.add_int(123);
//...
data.send_to_eeprom();
Last edited on
so I can break my ints and floats into bytes so they can be saved to an eeprom

you can do this directly.
float f;
unsigned char* cp = (unsigned char*)&f;
cp[0] .. cp[n] are the bytes of f -- you can use sizeof for the different types you need. Byte order of the machine may throw you -- remember that cp[0] could be most or least significant byte of an integer type depending on the local OS/platform.

you can craft all sorts of ways to do this and which approach may vary a bit depending on *what else* you need besides just byte level access. Are there any additional requirements beyond the byte access?
Last edited on
Like this, maybe?


I might be paranoid, but I'm working with 8kb RAM, so I'm not sure I'd want to use vector.
The lengths of the arrays will never change.
This still would have me adding all the different objects by name each time. I probably didn't ask my question very well.
If you're writing an object with a fixed structure then you can just use a struct.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct EepromMemory{
    int foo;
    float bar;
    int baz;
    //...
};

//Sanity check to make sure the compiler isn't doing
//shenanigans with the padding.
static_assert(sizeof(EepromMemory) == 48, "!!!");

EepromMemory mem;
mem.foo = 10;
mem.bar = .5f;
mem.baz = 123;
//...
send_to_eeprom(&mem, sizeof(mem));
so I can break my ints and floats into bytes so they can be saved to an eeprom

you can do this directly.
float f;
unsigned char* cp = (unsigned char*)&f;
cp[0] .. cp[n] are the bytes of f -- you can use sizeof for the different types you need. Byte order of the machine may throw you -- remember that cp[0] could be most or least significant byte of an integer type depending on the local OS/platform.

you can craft all sorts of ways to do this and which approach may vary a bit depending on *what else* you need besides just byte level access. Are there any additional requirements beyond the byte access?


For page writing to the eeprom the bytes need to be in a char array. The objects are used in the program and saved to eeprom by bank_num. So data would be saved or retrieved by the object names. so like this:
1
2
3
bits[1].inum
ratio[1].fnum
period[1].inum


but NOT this:
1
2
3
bits[1].inum
bits[2].inum
bits[3].inum


I think it would be easiest if I could somehow refer to all of this in a for loop in by elements [0] through [n], etc.

I was thinking something like this, but I think my syntax is wrong and I'm not sure it would take elements, especially not as variables.
1
2
3
4
5
6
7
typedef int (BankParam::*char_pointers)();

char_pointers make_char[48] = {&BankParam::bits[bank_num].byte_param[0], 
&BankParam::bits[bank_num].byte_param[1],&BankParam::bits[bank_num].byte_param[2],
&BankParam::bits[bank_num].byte_param[3],&BankParam::ratio[bank_num].byte_param[0],
&BankParam::ratio[bank_num].byte_param[1] //...more stuff
};
For page writing to the eeprom the bytes need to be in a char array.

No offense, but I do not believe you :)
I suspect a char* will work just fine there; in most cases (almost all) a char* and char array are interchangeable. Not always, so I could be wrong, but ....

the reverse also works: (I think this is what you were trying to do above?)
consider this (garbage code, but on an embedded system, it may be just what the DR ordered)

int index = 0;
char dafuq[1000];
int* ip1 = (int*) &dafuq[index];
index += sizeof(int);
int* ip2 = (int*) &dafuq[index];
index += sizeof(int);
double * dp1 = (double*) &dafuq[index];
index += sizeof(double);
...
your data will be in dafuq as a char array. you just made handles into the array to deal with groups of bytes as if they were the types in question. Any basic type (not stl containers, nothing with pointers inside it, same rules as serialization) can be done as above.

Last edited on
No offense, but I do not believe you :)


I'm using the I2C API from mbed. I believe it writes bytes to I2C from sequential memory. Any other type and it won't compile. (I've tried)

thanks for the other ideas though.
Any other type and it won't compile.
Pointers are pointers. Just cast to the appropriate type.
I believe it writes bytes to I2C from sequential memory. Any other type and it won't compile. (I've tried)

double d;
char* cp = (char*) &d;
cp is sequential bytes, sizeof(double) in length.
if you are trying to avoid calling the write a bunch of times for very small things and want to call it once for a larger block, the above reversed approach will do that, as will a carefully aligned struct and some pointer magic. I don't think the struct costs any more than the char array, and its a lot cleaner. deep down inside, its doing exactly the same thing, a block of bytes sliced up whatever way.
Last edited on
Topic archived. No new replies allowed.