Re: EEPROM, C++ a řetěžování operátorů
Miroslav Mraz
mrazik na volny.cz
Úterý Květen 30 17:41:20 CEST 2023
Dneska si s tím můžu trochu hrát, to se seznamem parametrů oddělených
čárkami skutečně jde napsat v šablonách. Já šablony dost nesnáším, ale
na druhou stranu se vyhodnocují patrně už při překladu, takže by to
mohlo být efektivnější než rodina printf().
#include <cstring>
#include <cstddef>
#include <iostream>
using namespace std;
/**************************** Balast *******************************/
constexpr int M=4;
struct Params { // data v EEPROM musí být stejně nějak popsána -
příklad
double a [M];
unsigned n;
float x;
};
static const Params eeprom = { // tohle by se muselo nějak do EEPROM zapsat
{1.0, 2.5, 5.0, 10.9},
1234'5678,
3.14159f,
};
static bool EEReadBytes (const size_t StartAddr, void * pval, const
size_t len) {
cout << "Read from " << StartAddr << ", len=" << len << endl;
const unsigned char * EEPROM = reinterpret_cast<const unsigned
char*>(&eeprom);
return memcpy (pval, EEPROM + StartAddr, len) == nullptr ? false : true;
}
/***************************** EEPROM ******************************/
template<typename T> class EEVar { // jednotlivá proměnná
T data;
public:
explicit EEVar (const size_t StartAddr) noexcept {
EEReadBytes (StartAddr, & data, sizeof(T));
}
operator const T () const {
return data;
}
};
template<typename T, const int N> class EEArray { // jednorozměrné pole
T data [N];
public:
explicit EEArray (const size_t StartAddr) noexcept {
EEReadBytes (StartAddr, & data, N * sizeof(T));
}
const T & operator[] (const int n) const {
return data [n];
}
// tady by se daly doplnit iterátory třeba pro range based for()
};
/***************************** PRINT ******************************/
template<typename T> void print(const T & t) { cout << t; } //
poslední parametr končí rekurzi
template<typename First, typename ... Rest> void print(const First &
first, const Rest & ... rest) {
cout << first; print(rest...); // rekurze až do konce - vše, co
tiskneme musí mít operator<< definován
}
/***************************** MAIN *******************************/
int main () {
EEVar<unsigned> x(offsetof(Params, n));
EEVar<float> r(offsetof(Params, x));
const float d = 2 * r; // počítat s tím jde -
operator const T dosadí překladač automaticky, pokud nemá jinou možnost
print("x = ", x, ", d = ", d, "\n"); // ani zde se nemusí
přetypovat, je to zřejmě jednoznačné
// pole
EEArray<double, M> arr(offsetof(Params, a));
cout << "params: "; // pro pole není žádný
problém, operátor[] je daleko jednoznačnější
for (int i=0; i<M; i++) print(arr[i], ", ");
cout << endl;
// arr[0] = 5.0 // nelze - read only
return 0;
}
Ani to není tak složité, jen nepřehledné a patrně dost spotřebovává
zásobník. Kdyby pro AVR fungoval clang, daly by se s tím asi dělat i
lepší kouzla - třeba parsovat fmt string při překladu. GCC si se
složitějšími výrazy v constexpr neporadí, dělá to pak v runtime, což je
otravné a velké.
Mrazík
On 30. 05. 23 1:15, Pavel Hudeček wrote:
> ...
>
> Co se cout vs prinft týče, tak nejvíc by se mi líbilo něco jako je print
> v klasickým Basicu, kdy tam napíšu seznam parametrů libovolných typů
> oddělených čárkama. Vlastně by se toho dalo dosáhnout přetížením
> operátoru čárka místo <<, jen to bude nestandardně vypadat:-)
Další informace o konferenci Hw-list