Следует ли использовать приведение для усечения длинной переменной? - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть 16-битная переменная без знака.Мне нужно разделить его на 8-битные куски.

Достаточно ли сделать следующее:

chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);

Или я должен использовать маску:

chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);

Я знаю, чтооба подхода работают, я просто ищу лучший способ сделать это, если таковой имеется.Может быть, нет и просто использовать приведение для сокращения вычислений это лучший способ?Что вы, ребята, думаете?

Ответы [ 4 ]

0 голосов
/ 25 февраля 2019

Не ясно, что типа variable.Без этого мы можем только строить предположения.

Но в целом следует избегать сдвига битов в целочисленных типах со знаком, так как это приводит к различным формам плохо определенного поведения.Это, в свою очередь, означает, что вы также должны быть осторожны с маленькими целочисленными типами, потому что они переводятся в число со знаком int.См. Неявные правила продвижения типов .

Конкретный случай (uint8)((variable >> 8) & 0xFFu); безопасен, если variable не подписано.В противном случае это небезопасно, поскольку смещение вправо отрицательного значения приводит к поведению, определяемому реализацией (арифметическое или логическое смещение).

variable << 8 вызовет неопределенное поведение в 16-битных системах в случае, если variable является небольшимцелочисленный тип или int16_t.

Таким образом, самый безопасный, самый переносимый способ независимо от смещения влево / вправо:

chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);

Хотя вам может потребоваться слишком явный порядокотключить все предупреждения компилятора:

chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
0 голосов
/ 25 февраля 2019

Поскольку uint8 без знака, у вас нет для маскировки:

6.3.1.3 Целые числа со знаком и без знака

  1. Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _ Bool, если значение может быть представлено новым типом, оно не изменяется.
  2. В противном случае, , если новый тип не подписан, значение преобразуется путем многократного сложения или вычитания более одного максимального значения, которое может быть представлено в новом типе, до тех пор, пока значение не окажется в диапазоне нового типа. 60)
  3. В противном случае новый тип подписывается и значение не может быть представлено в нем;либо результат определяется реализацией, либо генерируется определяемый реализацией сигнал.

Однако, скорее всего, оба результата приведут к одному и тому же выходу компилятора.Я обычно добавляю маску, потому что она ясно показывает, что код должен делать, и делает ненужным приведение.

0 голосов
/ 25 февраля 2019

Следует ли использовать приведение для усечения длинной переменной?

Если chunk_lsb является 8-битным объектом (уже variable), используйте приведение или маску (не оба).Полезно для успокоения педантичных предупреждений об уменьшении дальности.Я предпочитаю маску - если компилятор не разборчив.

uint8_t chunk_lsb = (uint8_t) variable;
// or 
uint8_t chunk_lsb = variable & 0xFFu;

В противном случае используйте маску.

unsigned chunk_lsb = variable & 0xFFu;
0 голосов
/ 25 февраля 2019

Может быть, нет ни одного, и лучше всего использовать приведение для сокращения вычислений?

Вообще говоря, код asm будет таким же, так что с точки зрения скорости он делаетНеважно, какой вы используете:

Что вы, ребята, думаете?

ИМО, первый из них более понятен с точки зрения читабельности, но я не могу понять стандарт кодирования или руководство, которое поддерживает мои предпочтения.В любом случае, я бы использовал переменную const, если вы предпочитаете второе, чтобы удалить магические числа и прояснить, что цель маскируется (при условии, что вы выбрали правильное имя для переменной const).

...