Подтвердить что ты не робот

Обмен двумя битами с одной операцией в C?

Скажем, у меня есть байт с шестью неизвестными значениями:

???1?0??

и я хочу обменять биты 2 и 4 (без изменения значений ?):

???0?1??

Но как бы это сделать в одной операции в C?

Я выполняю эту операцию тысячи раз в секунду на микроконтроллере, поэтому производительность является главным приоритетом.

Было бы хорошо "переключить" эти биты. Несмотря на то, что это не то же самое, что при замене битов, переключение будет отлично работать для моих целей.

4b9b3361

Ответ 1

Try:

x ^= 0x14;

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

x = precomputed_lookup [x];

где precomputed_lookup - это 256-байтовый массив, может быть самым быстрым способом, это зависит от скорости памяти относительно скорости процессора. В противном случае это:

x = (x & ~0x14) | ((x & 0x10) >> 2) | ((x & 0x04) << 2);

EDIT: дополнительная информация о переключении бит.

Когда вы xor (^) объединяете два целочисленных значения, xor выполняется на уровне бит, например:

for each (bit in value 1 and value 2)
   result bit = value 1 bit xor value 2 bit

так что бит 0 первого значения будет равен xor'ed с битом 0 второго значения, бит 1 с битом 1 и так далее. Операция xor не влияет на другие биты в значении. По сути, это параллельный бит xor для многих бит.

Глядя на таблицу истинности для xor, вы увидите, что xor'ing бит со значением "1" эффективно переключает бит.

 a  b a^b
 0  0  0
 0  1  1
 1  0  1
 1  1  0

Итак, чтобы переключать биты 1 и 3, напишите двоичное число с тем, где вы хотите, чтобы бит переключился, и нулем, где вы хотите оставить значение неизменным:

00001010

конвертировать в hex: 0x0a. Вы можете переключать столько бит, сколько хотите:

0x39 = 00111001

будет переключать биты 0, 3, 4 и 5

Ответ 2

Вы не можете "обменивать" два бита (т.е. биты меняют места, а не значение) в одной команде, используя бит-вождение.

Оптимальный подход, если вы действительно хотите обменять их, вероятно, является справочной таблицей. Это справедливо для многих "неудобных" преобразований.

BYTE lookup[256] = {/* left this to your imagination */};

for (/*all my data values */) 
  newValue = lookup[oldValue];

Ответ 3

Следующий метод НЕ является одной инструкцией на языке C, это просто еще один метод битбирования. Метод был упрощен из Обмен отдельных битов с XOR.

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

  • b: ваше исходное значение - 1? 0?? например
  • x: просто temp
  • r: результат

    x = ((b → 2) ^ (b → 4)) и 0x01
    r = b ^ ((x < 2) | (x < 4))

Быстрое объяснение: получите два бита, на которые вы хотите посмотреть, и XOR, сохраните значение до x. Переместив это значение обратно в биты 2 и 4 (и OR'ing вместе), вы получите маску, когда XORed с помощью b заменит ваши два оригинальных бита. В приведенной ниже таблице показаны все возможные случаи.

bit2: 0 1 0 1  
bit4: 0 0 1 1  
x   : 0 1 1 0   <-- Low bit of x only in this case 
r2  : 0 0 1 1  
r4  : 0 1 0 1

Я не полностью тестировал это, но для нескольких случаев, которые я пробовал быстро, он, похоже, работал.

Ответ 4

Это может быть не оптимизировано, но оно должно работать:

unsigned char bit_swap(unsigned char n, unsigned char pos1, unsigned char pos2)
{
    unsigned char mask1 = 0x01 << pos1;
    unsigned char mask2 = 0x01 << pos2;
   if ( !((n & mask1) != (n & mask2)) )
        n ^= (mask1 | mask2);
    return n;
}

Ответ 5

Нижеприведенная функция заменит биты 2 и 4. Вы можете использовать эту команду для предварительной компиляции таблицы поиска, если это необходимо (так что замена становится одной операцией):

unsigned char swap24(unsigned char bytein) {
    unsigned char mask2 = ( bytein & 0x04 ) << 2;
    unsigned char mask4 = ( bytein & 0x10 ) >> 2;
    unsigned char mask  = mask2 | mask4 ;
    return ( bytein & 0xeb ) | mask;
}

Я написал каждую операцию на отдельной строке, чтобы сделать ее более ясной.

Ответ 6

Скажите, что ваше значение равно x i.e, x =??? 1? 0??

Два бита могут быть переключены этой операцией:

x = x ^ ((1<<2) | (1<<4));

Ответ 7

#include<stdio.h>

void printb(char x) {
    int i;
    for(i =7;i>=0;i--) 
        printf("%d",(1 & (x >> i)));
    printf("\n");
}

int swapb(char c, int p, int q) {
    if( !((c & (1 << p)) >> p) ^ ((c & (1 << q)) >> q) )
        printf("bits are not same will not be swaped\n");
    else {
        c = c ^ (1 << p);
        c = c ^ (1 << q);
    }
    return c;
}

int main() 
{
    char c = 10;
    printb(c);
    c = swapb(c, 3, 1);
    printb(c);
    return 0;
}

Ответ 8

void swap_bits(uint32_t& n, int a, int b) {
    bool r = (n & (1 << a)) != 0;
    bool s = (n & (1 << b)) != 0;

    if(r != s) {
        if(r) {
            n |= (1 << b);
            n &= ~(1 << a);
        }
        else {
            n &= ~(1 << b);
            n |= (1 << a);
        }
    }
}

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

Используя ваш пример (n = ???1?0??), вы вызываете функцию следующим образом:

swap_bits(n, 2, 4);

Обоснование: вам нужно только поменять биты, если они разные (это почему r != s). В этом случае один из них равен 1, а другой равен 0. После этого просто обратите внимание, что вы хотите выполнить только одну операцию бит и одну операцию бит.