Каков наилучший способ подписать расширение числа в C / C

#c #c #bit

#c #c #бит

Вопрос:

У меня есть 10-битное значение со знаком. На самом деле это 10-битное значение цвета, которое я хочу преобразовать в int .

10 битов должны интерпретироваться как значение со знаком внутри большего int , где остальные биты равны нулю.

Я могу придумать 3 способа, показанных здесь:

 #include <stdio.h>

void p(int v)
{
    printf("t%d", v);
}

int main()
{
    for (int i = -2; i < 3;   i)
    {
        unsigned int u = i amp; 0x3ff;

        int v;

        // method 1: test the bit
        v = u;
        if (u amp; 0x200) v = v ^ -0x400;
        p(v);

        // method 2: shift
        v = u<<(sizeof(int)*8-10);
        v >>= (sizeof(int)*8-10);
        p(v);

        // method 3: use sign extend
        v = (signed char)(u >> 2);
        v <<= 2;
        v |= u;
        p(v);


        printf("n");

    }

    return 0;
}
  

есть ли способ лучше? Часто возникают проблемы с этим изменением бита.

Спасибо за любой ввод.

Обновить

Добавляем еще два метода. Первый, предложенный @cruz-jean, — это битовые поля, а второй, предложенный gcc после компиляции битовых полей.

       // method 4: bit fields
        struct { int v:10; } f;
        f.v = u;
        v = f.v;

        // method 5: sign extend short
        v = (signed short)(u << 6);
        v >>= 6;
  

Из интереса кажется, что MSVC компилирует # 4 в # 2, а gcc компилирует # 4 в # 5.

Метод 5 выглядит неплохо.

Комментарии:

1. Вы имеете в виду C или C ? Я сомневаюсь, что в вопросе должны быть оба тега.

2. Если у вас есть 10-разрядное значение со знаком, и вы хотите преобразовать его в int, вам нужно только выполнить приведение, ничего больше. Расширение знака означает только увеличение количества битов при сохранении значения и подписывается таким образом..

3. Если это значение является частью битового поля структуры, вы можете немного упростить его, просто объявив его как битовое поле со знаком — C / C выполнит все преобразования автоматически.

4. @Fredrik Я имел в виду, что 10 битов следует интерпретировать как подписанные, а не то, что они заполняют все слово. Извините, если неясно.

5. @FredLarson Это правда, что моя тестовая программа не будет компилироваться как C, но идея справедлива для обоих.

Ответ №1:

Вы могли бы объявить вспомогательный тип 10-разрядного подписанного битового поля и получить доступ к значению как int :

 struct signed_10_bit
{
    int val : 10;
};

int some_10_bit_num = 0x3ff;
int extended = signed_10_bit{ some_10_bit_num }.val;
  

Комментарии:

1. чтобы быть совместимым с C. Я изменил это на: struct {int v: 10; } f; f.v = u; v = f.v;

2. MSVC генерирует сдвиги, как в методе 2, но gcc сдвигается на 16 бит из 10, и знак расширяется там.

3. @jkjyuio Это в некотором роде хорошо. Напишите, что вы имеете в виду, и доверьте компилятору сделать это эффективно. Оптимизаторы в наши дни очень умны.

4. Спасибо. Я добавил ваше предложение. возможно, битовые поля — это способ.

Ответ №2:

Другой способ попробовать:

 v = u | (0 - (uamp;0x200));
  

подходит для процессоров, где сдвиг происходит медленно.

Комментарии:

1. Мне это нравится! Метод # 1 был мотивирован медленными сдвигами, но мне не понравился тест. Это лучше. Некоторые старые процессоры могут сдвигать только 1 за раз и нуждаются в цикле сдвига, так что это был бы лучший способ. Не уверен, какие битовые поля будут генерироваться для них.