Есть структура:
#pragma pack(push, 1)
struct protocol_header {
uint32_t sign = 42;
uint8_t checksum = 0;
uint8_t length = 6;
constexpr protocol_header(void) {
checksum += sign & 0xFF000000 >> 24;
checksum += sign & 0x00FF0000 >> 16;
checksum += sign & 0x0000FF00 >> 8;
checksum += sign & 0x000000FF >> 0;
m_checksum += length;
m_checksum = 0x100 - m_checksum;
}
};
#pragma pack(pop)
и объявление может быть таким. Главное чтобы заголовок попал в нужную секцию!
__attribute__((section(".protocol_header_section"))
static protocol_header;
Требуется во время компиляции занести в поле checksum побайтовую сумму этой структуры.
"Плохое" решение приведено.
Размер реальной структуры больше. Поэтому складывать байты вручную не получится.
Если нужны вычисления именно при компиляции, то можно это сделать несколькими вариантами.
Через #define-макрос влоб (если структура одна)
#pragma pack(push, 1)
#define protocol_header_sign 42
#define protocol_header_len 6
struct protocol_header {
uint32_t sign = protocol_header_sign ;
uint8_t checksum = (protocol_header_sign & 0xFF) + protocol_header_len /*+И так далее*/;
uint8_t length = protocol_header_len;
};
#pragma pack(pop)
Так же можно сделать шаблонный #define (#define PROTOCOL_HEADER(SIGN,LEN) struct{...
) но шаблон template практичнее.
Второй способ - через шаблон, если структур две и более то подходит. Для структуры будет создано несколько "экземпляров", в отдельных случаях это полезно.
#pragma pack(push, 1)
template < uint32_t SIGN,uint8_t LEN> struct protocol_header {
uint32_t sign = SIGN;
uint8_t checksum = (SIGN & 0xFF) + LEN /*+ и так далее*/;
uint8_t length = LEN;
};
#pragma pack(pop)
protocol_header<42,6> myprotocol1;
Только тогда в полях будут константные выражения, и расчёт будет сделан компилятором. Переменные в константые выражения подставлять нельзя (и в protocol_header<42,6>
тоже нужно подставлять строго константы).
Ну и на десерт, вариант с пред-инициализацией структуры, в отдельных случаях подходит. Думаю это самый практичный вариант. В отличии от предыдущих двух - не будет плодится кучи копий класса. protocol_header mystruct={ 42, выражение, 6 }
, что можно завернуть в #define макрос, который так же можно использовать повторно.
#define init_protocol_header (SIGN,LEN) {SIGN,(SIGN & 0xFF) + LEN /*+ и так далее*/, LEN }
protocol_header mystruct = init_protocol_header (42,6);
В итоге компилятор инициализирует переменную в mystruct, и либо будет использовать push/memcpy для инициализации в локальной области, либо забьет посчитанные константы в BSS, при обьявлении в глобальной области.
Если имена полей нельзя терять, то самый простой вариант - добавить constexpr функции:
// предется вручную прописывать для всех используемых типов, кроме uint8_t ...
constexpr uint8_t calc_hi(uint16_t i) { return static_cast<uint8_t >( (i>>8) ); }
constexpr uint16_t calc_hi(uint32_t i) { return static_cast<uint16_t>( (i>>16) ); }
constexpr uint32_t calc_hi(uint64_t i) { return static_cast<uint32_t>( (i>>32) ); }
constexpr uint8_t calc_low(uint16_t i) { return static_cast<uint8_t >( i ); }
constexpr uint16_t calc_low(uint32_t i) { return static_cast<uint16_t>( i ); }
constexpr uint32_t calc_low(uint64_t i) { return static_cast<uint32_t>( i ); }
constexpr uint8_t calc_checksumm(uint8_t i) { return i; }
template<typename T>
constexpr uint8_t calc_checksumm(T i)
{
return calc_checksumm( calc_hi(i) ) + calc_checksumm( calc_low(i) ) ;
}
template<typename A0, typename ... Args>
constexpr uint8_t calc_checksumm(A0 a0, Args...args)
{
return calc_checksumm(a0)+calc_checksumm(args...);
}
template<typename T>
constexpr uint8_t calc_len(T ) { return sizeof(T); }
template<typename A0, typename ... Args>
constexpr uint8_t calc_len(A0 a0, Args...args)
{
return calc_len(a0)+calc_len(args...);
}
struct protocol_header {
uint32_t sign = 42;
uint64_t sign2 = 24;
// Типы Важны! Но можно убрать списки в один define.
uint8_t checksum = calc_checksumm((uint32_t) 42, uint64_t(24))
+calc_len ((uint32_t) 42, uint64_t(24));
uint8_t length = calc_len ((uint32_t) 42, uint64_t(24));
};
Здесь есть существенный недостаток - список типов и значений повторяется четыре раза. Можно слегка сгладить этот недостаток define-ами.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Здраствуйте, пробую реализовать арканоид, но столкнулся с проблемой, что текстуры привязуется к не правильным участкам пространстваУ меня...
ООП в плюсах для меня тема новаяНужно написать класс my_sample который должен иметь среди своих приватных полей вектор long double, который назвать...
А для чего нужны спецификации исключения noexcept(true) и noexcept(false), как и когда они используются?