Я выполняю операцию с байтами, где хочу добавить uint8 к MSB существующего uint32:
uint32 my_uint32;
my_uint32 = 0x00ffffffu;
my_uint32 = (uint32)(my_uint32) | ((uint8)(0x2u) << 24u)); // Add value 0x02 to the MSB of my_uint32
my_uint32 = 0x02ffffffu // This is what I get and is working so far
Это пока нормально, но я получаю предупреждение:
"Выражение, являющееся результатом операции ~ или <<, не было приведено к своему основному типу"
Я могу избавиться от предупреждения, выполнив:
my_uint32 = ((uint32)(my_uint32) | (uint8)((0x2u) << 24u)); // Here I'm doing the uint8 cast on the complete shift operation
Но чем это не сработает. Результат будет:
my_uint32 = 0x00ffffffu
Кто-нибудь знает, как я могу избежать предупреждения?
Я не могу воспроизвести это с uint8_t
и uint32_t
, так что, может быть, это артефакт ваших (нестандартных?) типов? Используется clang
, который обычно довольно сварлив и совершенно холоден, ноль предупреждений.
@tadman: Правильно. Но первое решение точно сработает. Но как избавиться от предупреждения, чем?
Это сообщение от компилятора или от инструмента MISRA? Каков размер int
в вашей реализации C?
@EricPostpischil: это предупреждение MISRA. Размер int 32 бита,
Почему вы используете такое приведение типов, если результат сразу же преобразуется снова? Почему бы не использовать более подходящий тип?
Это должно работать:
my_uint32 = (uint32)(my_uint32) | (uint32)((uint32)(uint8)(0x2u) << 24u));
Но можно сократить до этого:
my_uint32 = (uint32)(my_uint32) | (uint32)((uint32)(0x2u) << 24u));
Извините, но это не имеет никакого смысла и, конечно же, не требуется для MISRA-C.
@Lundin Я не совсем знаком с MISRA-C, но предполагая, что uint32
ведет себя как стандарт uint32_t
, цель приведения (uint32)
к левому операнду <<
состоит в том, чтобы гарантировать, что смещаемое значение имеет 32 бита значения, а намерение приведения (uint32)
к результату операции <<
должно соответствовать данному предупреждению «Выражение, являющееся результатом операции ~ или <<, не было приведено к его основному типу» (что бы ни означал «основной тип»!) .
Если мы игнорируем 16-битную int
систему, то этот код делает следующее: 2u
= дайте мне беззнаковое целое, не ждите, я передумал дайте мне uint8, не ждите, я передумал, дайте мне uint32, как у меня было из start, shift, затем конвертируйте из uint32 в uint32. Все это бессмысленно.
Предупреждение касается неправильного приведения uint8, которое следует просто удалить. Я опубликовал ответ, объясняющий это.
@Lundin Думаю, теперь я понял. Предупреждение было выдано из-за того, что результат оператора <<
не приводился к типу левого операнда <<
, который является «основным типом». Приведение к (uint8)
послужило бы цели, если бы оно усекало операнд.
Замените my_uint32 = (uint32)(my_uint32) | ((uint8)(0x2u) << 24u));
на my_uint32 = my_uint32 | ((uint32) 0x2u << 24);
.
По существу, левый операнд сдвига должен быть преобразован в желаемый тип результата, чтобы сдвиг выполнялся с этим типом. Приведение его к uint8
приводит к тому, что сдвиг выполняется с типом int
из-за автоматического повышения.
Также нет необходимости приводить к uint32
, если только система не использует 16-битные целые числа или не должна быть переносима на такие системы. Код уже был совместим с MISRA еще до того, как началось все это преобразование.
@Lundin: В этом конкретном значении нет необходимости, но в будущем его можно легко изменить на 0x80
или какой-либо макрос, и я подумал, что MISRA и / или OP могут захотеть, чтобы форма выражения была правильной независимо от операнда. сдвинутый.
Это означает, что операнд (uint8)(0x2u)
неявно повышается до int
, который является подписанным. Такие рекламные акции могут вызывать тонкие ошибки.
Некоторые старые рекомендации MISRA заключаются в том, чтобы впоследствии привести к основному типу, чтобы гарантировать, что тип выражения остается согласованным:
(uint32_t)(some_uint8_t << 24)
Тем не менее, я бы лично порекомендовал сделать это приведение явно перед сдвигом, чтобы вы не рисковали продвижением типа до знакового типа, а затем случайными сдвигами, когда вы оставили биты сдвига в бит знака или сдвиг вправо с сохранением знака (арифметический сдвиг) и т.д. То есть сделать так:
(uint32_t)some_uint8_t << 24
Это лучшая практика для всех 32-битных систем.
Однако в вашем конкретном случае проблема здесь: (uint8)(0x2u)
.
2u
уже имеет тип unsigned int
, который уже является правильным типом для битового сдвига на 24. (Если это не система с 16-битным int
, в этом случае приведение к uint8
также не имеет никакого смысла.)
Просто отбросьте все странные слепки! Этот код соответствует требованиям MISRA-C:
my_uint32 = my_uint32 | (0x2u << 24u);
Вам нужно привести этот операнд только в том случае, если вам нужен код для работы в 16-битных системах, и в этом случае вы можете сделать либо (uint32)0x2u
, либо 0x2ul
, любой из них подходит и совместим с MISRA.
2<<24
слишком велик для 8 бит, т.е.(uint8)(2<<24) == 0