gcc — Преобразование дополнения 2 значений вперед и назад в C ++ с помощью вычисления или приведения?

Я получаю некоторые значения из аппаратных регистров, где значения хранятся в 16-разрядных целых числах без знака, но эти значения на самом деле подписаны. Зная, что последний бит является знаковым битом, коллега сделал следующий фрагмент кода, чтобы преобразовать их в значения дополнения 2:

/* Take 15 bits of the data (last bit is the sign) */
#define DATAMASK 0x7FFF

/* Sign is bit 15 (starting from zero) with the 15 bit data */
#define SIGNMASK 0x8000
#define SIGNBIT  15int16_t calc2sComplement(uint16_t data)
{
int16_t temp, sign;
int16_t signData;

sign  = (int16_t)((data & SIGNMASK) >> SIGNBIT);

if (sign)
{
temp = (~data) & DATAMASK;
signData = (short)(temp * -1);
}
else
{
temp = (data & DATAMASK);
signData = temp;
}

return(signData);
}

Насколько я знаю, целые типы без знака и целые числа со знаком отличаются только по их типу и значению последнего бита; так что приведение типа следующее должно также работать:

int16_t calc2sComplement(uint16_t data)
{
return(static_cast<int16_t>(data));
}

и когда необходимо передать значения аппаратным средствам, обратная операция проста, в отличие от расчета. Преимущество первого решения заключается в отсутствии инструментов; так как он может измениться рано или поздно (gcc 4.4.7 и т. д. C ++ 03), я бы предпочел не делать этого, но не будет регрессии при компиляции спустя годы. Преимущество последнего в том, что он более читабелен, близок к стандарту и позволяет избежать ненужных операций.

Что было бы лучше всего в моем случае, чтобы быть уверенным, чтобы сохранить то же поведение, если компилируется снова после изменения цепочки инструментов (даже стандартные типы переопределены где-то в инструментальной цепочке, и я не очень-то понимаю)
Если вы оставите первое решение, как его улучшить и / или закодировать обратное преобразование (имейте в виду, что данные могут быть указателем на буфер данных)?

0

Решение

В конце давайте ответим себе. Таким образом, лучший способ преобразовать значения в или из дополнения до двух и предотвратить непредвиденное поведение — выполнить преобразование дополнения до двух следующим образом:

int16_t calc2sComplement(uint16_t data)
{
return(static_cast<int16_t>(data));
}

и сделать обратную операцию:

uint16_t inv2sComplement(int16_t data)
{
return(static_cast<uint16_t>(data));
}

Этот метод оказался полностью безопасным (если типы примитивов не переопределены где-то в цепочке инструментов — что считается плохой практикой, но на самом деле это был мой случай, а следовательно, и мой вопрос в первую очередь), опираясь на определение построенного примитива. в типах.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]