Преобразование 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  15


int16_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), я бы предпочел не делать этого, но не будет регрессии при компиляции спустя годы. Преимущество последнего в том, что он более читабелен, близок к стандарту и позволяет избежать ненужных операций.

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

1 ответ

Решение

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

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

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

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

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

Другие вопросы по тегам