Я предположил, что предлагаемый подход не следует строгому правилу наложения имен
Правильно. ptrMsg = (Message *)buffer
означает, что вы не можете получить доступ к данным ptrMsg
без вызова неопределенного поведения.
Вы можете доказать свою точку зрения с помощью C17 6.5 §7 (здесь цитируется - Что такое строгое правило псевдонимов? ). Выражение lvalue, такое как ptrMsg->var1 = value
, не обращается к сохраненному значению ни через тип, совместимый с эффективным типом того, что там хранится, ни через любое из разрешенных выражений.
Однако вы можете перейти от Message
к массиву uint8_t
(при условии, что uint8_t
является типом символа) без нарушения строгого псевдонима.
Однако более серьезной проблемой является приоритет битового поля, которое является нестандартным и непереносимым. Например, вы не можете знать, какая часть битового поля является MSB и LSB. Вы не можете знать, как биты выровнены в 64-битном типе. Использование 64-битного типа для битового поля является нестандартным расширением. Это зависит от endianess. И так далее.
Если предположить, что 24 бита относятся к битам с 31 по 8 (мы не можем узнать, читая ваш код), тогда правильный код без строгих нарушений псевдонимов, безумия битового поля и нестандартных «убийц структурных заполнителей» будет выглядеть следующим образом :
typedef union
{
uint32_t var;
uint8_t bytes[4];
} Message;
uint8_t buffer[4];
Message* ptrMsg = (Message*)buffer;
uint32_t var1 = (ptrMsg->var >> 8);
uint8_t var2 = (ptrMsg->var >> 4) & 0x0F;
uint8_t var3 = (ptrMsg->var) & 0x0F;
Message
, являющийся "типом объединения, который включает один из вышеупомянутых типов среди своих
members ". То есть содержит тип, совместимый с uint8_t [4]
.
Этот код также не содержит копирования, и сдвиги будут переведены в соответствующий битовый доступ в машинном коде.