Как говорит ouah , преобразование значения вне диапазона дает результат, определенный реализацией (или позволяет повысить сигнал, определяемый реализацией).
Например,для реализации было бы совершенно правильно сказать, что преобразование значения вне диапазона в int16_t
сохраняет только младшие 15 битов значения и всегда устанавливает бит знака в 0. Таким образом, это будет интерпретировать ваш sign_extend16()
функция просто return val & 0x7fff;
.
Однако реализация не может интерпретировать вашу функцию так, что она просто возвращает val
без изменений - преобразование, определенное реализацией, в int16_t
должно приводить к значению где-то в диапазоне int16_t
, поэтому конечный результат должен находиться где-то в [0, 32767]
или [4294934528, 4294967295]
.
Обратите также внимание, что приведение int32_t
там совершенно излишне.
Две альтернативы, которые не зависят от преобразований, определенных реализацией: (обратите внимание на изменение типа аргумента val
):
uint32_t se16(uint16_t val)
{
return -((uint32_t)val << 1 & 0x10000) | val;
}
uint32_t se16(uint16_t val)
{
return (val ^ (uint32_t)32768) - (uint32_t)32768;
}
... но, к сожалению, gcc optКажется, что imiser не замечает, что это просто расширение знака младших 16 бит.