Установка бита беззнакового символа с другим битом другого беззнакового символа без условного

Я использую побитовое для включения и выключения битов следующим образом:

unsigned char myChar = ...some value
myChar |= 0x01 << N // turn on the N-th bit

myChar &= ~(0x01 << N) //turn off the N-th bit

Теперь предположим, что значение N известно, но операция установки/снятия зависит от значения бита другого беззнакового символа. С этого момента я делаю так:

if ((otherChar & (0x01 << M)) != 0)
{
    //M-th bit of otherChar is 1
    myChar |= 0x01 << N; 
}else
{
    myChar &= ~(0x01 << N);
}

Это должна быть своего рода операция «перемещения бита» из беззнакового символа в другой.

Мой вопрос: есть ли способ сделать это без использования условного? (и без std::bitset тоже)


person Heisenbug    schedule 23.06.2012    source источник
comment
Когда вы говорите N-th bit, это считается с нуля?   -  person Nawaz    schedule 23.06.2012
comment
да.. на основе нуля. Это актуально?   -  person Heisenbug    schedule 23.06.2012


Ответы (3)


Краткий ответ - да".

Более длинный ответ заключается в том, что вы используете бит непосредственно из источника:

unsigned char bit = 1 << N;

myChar &= ~bit;             // Zero the bit without changing anything else
myChar |= otherChar & bit;  // copy the bit from the source to the destination.

Это предполагает, что вы хотите скопировать бит N из источника в бит N адресата. Если биты источника и назначения могут иметь разные смещения, все становится немного сложнее. Вы должны не только извлечь правильный бит из источника, но затем вам нужно переместить его в правильное место, а затем ИЛИ в место назначения. Основная идея примерно такая же, как и выше, но код для переключения немного утомителен. Проблема в том, что вы хотите сделать что-то вроде:

unsigned char temp = source & 1 << M;
temp <<= N - M;
dest |= temp;

Это будет работать нормально, если N> M, но если M> N, вы получите что-то вроде temp <<= -3;. Вам хотелось бы, чтобы сдвиг влево на -3 превратился в сдвиг вправо на 3, но это не то, что происходит, поэтому вам нужен некоторый условный код, чтобы получить абсолютное значение и выяснить, нужно ли сделать сдвиг вправо или влево, чтобы получить бит от источника в правильное место в месте назначения.

person Jerry Coffin    schedule 23.06.2012
comment
@MarkTolonen: Вы правы, он использовал переменные не так, как в вопросе. Я переписал его, чтобы использовать те же (я думаю, во всяком случае) переменные так же, как он сделал в вопросе. - person Jerry Coffin; 23.06.2012
comment
Да ты прав. Сначала он отвечает не совсем правильно, но я понял. - person Heisenbug; 23.06.2012
comment
Как насчет dest |= ((source >> M) & 1) << N? - person fredoverflow; 23.06.2012
comment
@FredOverflow: Хорошее замечание - похоже, это тоже должно сработать. - person Jerry Coffin; 23.06.2012

Одно из решений состоит в том, чтобы сначала всегда сбрасывать бит, а затем побитово или в соответственно смещенной и замаскированной версии otherChar.

person Oliver Charlesworth    schedule 23.06.2012

Это читает бит from c1 и записывает его в бит to c2.

#include <stdio.h>

typedef unsigned char uchar;

uchar move_bit(uchar c1, int from, uchar c2, int to)
{
    int bit;
    bit = (c1 >> from) & 1;            /* Get the source bit as 0/1 value */
    c2 &= ~(1 << to);                  /* clear destination bit */
    return (uchar)(c2 | (bit << to));  /* set destination bit */
}

int main()
{
    printf("%02X\n",move_bit(0x84,3,0x42,5));
    printf("%02X\n",move_bit(0x81,0,0x03,7));
    printf("%02X\n",move_bit(0xEF,4,0xFF,6));
    return 0;
}

Результат:

42
83
BF
person Mark Tolonen    schedule 23.06.2012