Вопрос, апятьже, к "икспердам"
- Войдите на сайт для отправки комментариев
Ср, 25/03/2020 - 11:42
есть структура из битовых полей, без методов, размером в 1 байт
struct TAHTStatus {
public:
uint8_t Reserved : 3;
bool Calibrated : 1;
bool Reserved2 : 1;
enMode WorkMode : 2;
bool Busy : 1;
};
как можно байт ответа устройства привести к типу этой структуры без таких костылей?
TAHTStatus GetStatus(void) {
Wire.requestFrom(FDevAddress,1U); // запрашиваем байт статуса
uint8_t status = Wire.read(); // читаем его
TAHTStatus result; // создаем временный обьект, чтоб его отдать
uint8_t *tmp = (uint8_t *)(&result); // применяем костыли
*tmp = status; // копируем в них
return result; // и возвращаем
}
memcpy() наерна можно применить, но это тоже костыли. А static_cast<TAHTStatus>(status) не работает, пишет, нет такова конструктора. Чёртичо, короче, и сбоку бантег. В Delphi хоть absolute есть.
канеш, так memcpy(&result, &status, 1); тоже работает, но ить некрасива же.
reinterpret_cast. Для static_cast нужно правила объявлять.
так он же для пойнтеров только, а у меня оба типа-значения одного размера
Allows any pointer to be converted into any other pointer type
наерна, проще будет в структуру конструктор запилить
struct TAHTStatus { public: uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; TAHTStatus(uint8_t value) { memcpy(this, &value, 1); }; };Наскока это безопасно?
наерна, проще будет в структуру конструктор запилить
struct TAHTStatus { public: uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; TAHTStatus(uint8_t value) { memcpy(this, &value, 1); }; };Наскока это безопасно?
С точки зрения COVID-19? Ну руки воткой протри, штоле!
Дет, ты ж нормальный программист, а иногда тебя заносит, аж жуть! ;))) По трезвяку верно?
------------------------
Если под "безопасно" ты понимаешь страховку от неработоспособности в новой версии GCC, то Женя тебе объяснит, что такой страховки не бывает! ;))) В комитете - такие затейники! Даже я краснею, бывает.
Дет, ты ж нормальный программист, а иногда тебя заносит, аж жуть! ;)))
Чойта? Я реально иногда нихрена в этом лжывом С++ не понимаю, не родной он мне, не привыкну всё, что никогда нельзя сказать точно, что сегодня с утра значит оператор присваивания, к примеру. Да и программист из меня - как из авна пуля, особенно в последние годы. :)
Деда, первое, что нужно сделать - это принудительно указать компилеру на выравнивание структуры по границе байта:
#pragma pack(push,1) struct TAHTStatus { public: uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; }; #pragma pack(pop)В случае, когда у тебя там будет битовых полей и прочей чепухи больше, чем на один байт - ты будешь уверен, что всё идёт последовательно, без выравниваний, которые применяет компилятор так, как ему хочется.
Второе - можно применить побайтовое копирование, отдав это дело на откуп компилятору, и без memcpy:
#pragma pack(push,1) struct TAHTStatus { public: uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; uint8_t WorkMode : 2; bool Busy : 1; }; #pragma pack(pop) void setup() { uint8_t someByte = 0xD0; TAHTStatus status = *reinterpret_cast<TAHTStatus*>(&someByte); } void loop() { }Я только enMode заменил на uint8_t, т.к. не знаю, чего это за тип у тебя.
Дед, ну, конечно, можно и прямо преобразовывать типы, никто не мешает, только аккуратно. Например, можно написать вот так:
enum enMode { Nefig, Nafig, Pofig }; struct TAHTStatus { public: uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; }; void setup(void) { TAHTStatus kaka = * (TAHTStatus *) & PORTB; PORTC = * (uint8_t *) & kaka; } void loop(void) {}Но я бы так писать не стал. И memcpy тоже не стал бы использовать. Вместо этого я бы сделал из структуры union и использовал бы простое присваивание. Примерно вот так:
enum enMode { Nefig, Nafig, Pofig }; union TAHTStatus { inline TAHTStatus(const uint8_t v = 0) { _cover = v; } struct { uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; }; private: uint8_t _cover; }; void setup(void) { TAHTStatus kaka = PORTB; } void loop(void) {}Обрати внимание, что структура, которая сидит внутри union не имеет никакого имени. Это важно! Именно это позволяет обращаться к её членам напрямую (например, kaka.Calibrated). Если бы у неё было имя, то пришлось бы тащить его всё время.
Но это половинчатое решение. А как быть с обратной задачей, не впихнуть в твою структуру какое-то значение, а наоборот её значение запихать куда-то? Можно добавить переопределение операторов присваивания и приведения типа, но тут засада - у юнионов операторы не переопределяются. Выход, например, такой - запихать union в ещё одну структуру и уже у неё всё, что надо переопределить (при этом помним про то, что без крайней нужды имена никуда не пихаем!). Получается что-то типа:
enum enMode { Nefig, Nafig, Pofig }; struct TAHTStatus { union { struct { uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; }; uint8_t _cover; }; inline operator uint8_t & () { return _cover; } inline uint8_t operator = (const uint8_t v) { return _cover = v; } inline TAHTStatus(const uint8_t v = 0) { _cover = v; } }; void setup(void) { TAHTStatus kaka = PORTB; PORTC = kaka; } void loop(void) {}На самом деле, можно ещё кучу способов предложить, но такой, вроде, всё, что нужно делает и к полям можно прямо обращаться, типа kaka.Calibrated
Все рассмотренные решения (включая и твоё с memcpy) абсолютно идентичны по ресурсам (память там и быстродействие) - код получается просто одинаковый.
Спасибо, парни, остановился на этом, если подводных камней нет, то меня полностью устра.
enum enMode { NOR = 0, CYK = 1, CMD = 2 }; #pragma pack(push,1) struct TAHTStatus { public: uint8_t Reserved : 3; bool Calibrated : 1; bool Reserved2 : 1; enMode WorkMode : 2; bool Busy : 1; TAHTStatus(uint8_t value) { memcpy(this, &value, 1); }; }; #pragma pack(pop) . . . . TAHTStatus GetStatus(void) { Wire.requestFrom(FDevAddress,1U); return (Wire.read() & 0xFF); }Деда, первое, что нужно сделать - это принудительно указать компилеру на выравнивание структуры по границе байта:
Спасибо, я это всегда делаю теперь на уровне спинного мозга, где надо, и где не надо. :)
Спасибо, парни, остановился на этом, если подводных камней нет, то меня полностью устра.
В приведённом примере - подводных камней нет, если меня зрение не подводит. Однако, чем тебя не устраивает reinterpret_cast? В твоём случае - ты жёстко привязываешься к байту. В случае с reinterpret_cast - компилятор сам скопирует в структуру всё, что находится по указателю. Расширил объявление структуры - оно автоматически скопируется из источника, приведённого к типу указателя на структуру. Конечно, и этим способом можно себе ногу прострелить, залазя в память не тудыть.
Короче, делай как нравится, вариантов, как видишь, всегда есть ;)
Спасибо. :-)
На срецтво, дет, на срецтво. Виш кака эпидерсия вакрук, срецтво + перец + агурец = вот нашефсё!!!
В приведённом примере - подводных камней нет, если меня зрение не подводит. Однако, чем тебя не устраивает reinterpret_cast?
Ненавижу звёздочки, скопки и их комбинацыи. :) Пока разберешься, чо к чему относица - уже, глядишь, и плюшевый вхлам.
Обрати внимание, что структура, которая сидит внутри union не имеет никакого имени. Это важно! Именно это позволяет обращаться к её членам напрямую (например, kaka.Calibrated). Если бы у неё было имя, то пришлось бы тащить его всё время.
Вот не знал, категорически блаадарю. :) Иногда так ломает в union struct пхать, именно из-за обилия точек в такой переменной, аж в глазах рябит, теперь знать буду. :) Век живи - а дураком памрёшь.
Понятное дело, мы с моим стратегическим запасом мяса и шерсти теперь столько валерянки накупим...
Скотокот одобряэ.
Хорошо когда белый - все блохи как на ладони. Не то что у моего чёрного.(