Ответ 1
Это integer promotions
на работе.
в
x |= y;
оба операнда оператора |
продвигаются до int
x = (int)x | (int)y;
тогда результат преобразуется обратно в uint8_t
, теряя точность.
Я обычно понимаю причину предупреждения компилятора, но это кажется просто неправильным.
#include <stdint.h>
uint8_t myfunc(uint8_t x,uint8_t y)
{
x |= y;
return x;
}
Компилятор Intel с -Wall жалуется:
conversion from "int" to "uint8_t={unsigned char}" may lose significant bits
x |= y;
^
Правильно ли это? Является ли приведенный выше код не переносимым и нестандартным каким-то образом?
Это integer promotions
на работе.
в
x |= y;
оба операнда оператора |
продвигаются до int
x = (int)x | (int)y;
тогда результат преобразуется обратно в uint8_t
, теряя точность.
Это правильно. Оператор продвигает аргумент (аргументы) до int
. Подробнее см. эту страницу, начнется первое предложение:
Арифметика не выполняется с помощью C с точностью короче int [...]
Значения x
и y
для вычисления вычисляются до int
, но предупреждение все же является фиктивным. Оператор |
не может увеличивать ширину в битах результата за пределами ширины операндов, которые уже вписываются в uint8_t
, поскольку они были продвинуты с uint8_t
. Подавляющее большинство этих флагов флажков с предупреждением являются полностью верным и правильным кодом, и, если вы не хотите тратить свое время на 100 таких вопросов, я думаю, что лучше всего отключить или игнорировать эти предупреждения.
Предупреждение о компиляторе может показаться бессмысленным, потому что операция не может производить более 8 бит, но это всего лишь подмножество большего класса операций, которое может. Например, если вы заменили |=
на +=
, возможность переполнения станет очень реальной.
Способ устранения предупреждения состоит в том, чтобы сообщить компилятору, что вы сознательно выбрасываете биты с помощью:
x = (uint8_t)(x | y);