Битовые операции (поменять местами два соседних бита в числе)

Язык: Си. Нужны корректировки к коду и помощь с ним. Цель: написание программы, которая будет получать с клавиатуры целое число и возвращать другое число, где переставлены местами соседние биты (0 и 1, 2 и 3, 4 и 5 и т.д). Например:

Введено: 163 = 0хА3 = 10100011 Результат: 83 = 0х53 = 01010011

  1. Вводится «новый» тип данных:
typedef unsigned int integer_tp;
//typedef unsigned short integer_tp;
//typedef unsigned char integet_tp;
//typedef unsigned long integer_tp;
  1. Результат: числа в десятичной, шестнадцатеричной и двоичной СС (и входное, и результат)

Проблемы:

  1. Не понимаю, как можно изменить код, чтобы сам обмен битов производился без «вспомогательного» массива. Я понимаю, что решение этой зэчасти задачи в целом странное, поэтому и хотелось бы попросить предложить иное. Спасибо!
  2. Где и как именно корректно использовать еще один тип тип maxint, чтобы он решал следующую проблему: все эти типы данных имеют разный размер, из-за чего тоже возникают сложности, поскольку число нужно считывать с клавиатуры. Если использовать один и тот же флаг, то будут и переполнения, и, наоборот, может быть недостаточно данных. Размер maxint соответствует максимальному из предложенных выше типов данных для integer_tp. Не пишите, пожалуйста, о том, что в коде ниже путаница со считыванием и выводом типов данных, я вижу это, но не знаю, как изменить.

Код:

#pragma warning(disable: 4996) 
#include <stdio.h> 
#include <locale.h> 
#include <limits.h> 
 
typedef unsigned int integer_tp; 
// typedef unsigned short integer_tp; 
// typedef unsigned char integet_tp; 
// typedef unsigned long integer_tp; 
 
typedef unsigned long maxint; 
 
integer_t process(integer_tp b) { 
 int f, i; 
 unsigned int m[4] = { 0,2,1,3 }; 
 for (i = 0; i < 8*sizeof(integer_tp); i += 2) { 
 f = (b >> i) & 3; 
 b = (b & (~(3 << i))) | (m[f] << i); 
 } 
 printf("%d", b); 
} 
 
void tobin(integer_tp g) { 
 if (g == 0) { 
 printf("\n"); 
 return; 
 } 
 printf("%ld", g & 1); 
 tobin(g >> 1); 
} 
 
int main() { 
 maxint m; 
 printf("Введите число: "); 
 scanf("%lu", &m); 
 process(m); 
 return 0; 
}

Ответы (2 шт):

Автор решения: Harry

Вам надо два конкретных бита?

Вот обмен i-го и j-го битов в переменной b:

unsigned int swap(unsigned int b, unsigned int i, unsigned int j)
{
    if (i > j) { unsigned int t = i; i = j; j = t; }
    unsigned int maski = 1u << i;
    unsigned int maskj = 1u << j;
    return ((b&maski) << (j-i)) | ((b&maskj) >> (j-i)) | (b&~(maski|maskj));
}

Или задача обменять все пары битов? Для всех пар это делается еще проще:

unsigned int pair_swap(unsigned int b)
{
    return ((b&0x55555555) << 1) | ((b&0xAAAAAAAA) >> 1);
}

Даже распишу :)

b                  abcdefghijklmnopqrstuvwxyzABCDEF
0x55555555         01010101010101010101010101010101
b & 0x55555555     0b0d0f0h0j0l0n0p0r0t0v0x0z0B0C0F
b&0x55555555 << 1  b0d0f0h0j0l0n0p0r0t0v0x0z0B0C0F0

0xAAAAAAAA         10101010101010101010101010101010
b & 0xAAAAAAAA     a0c0e0g0i0k0m0o0q0s0u0w0y0A0C0E0
b&0xAAAAAAAA >> 1  0a0c0e0g0i0k0m0o0q0s0u0w0y0A0C0E

b&0x55555555<<1 |
b&0xAAAAAAAA>>1    badcfehgjilknmporqtsvuxwzyBADCFE
→ Ссылка
Автор решения: Виктор

Такой вариант:

// Функция для замены 'b' битов, 
// начиная с позиции 'p' и 'q', в целом числе 'n'
int swap(int n, int p, int q, int b)
{
    int x = ((n >> p) ^ (n >> q));
    x = x & ((1 << b) - 1);
    return n ^ ((x << p) | (x << q));
}
 
int main()
{
    int n = 0xAA;       // исходное число
    int p = 0, q = 1;   // p - bit №1      q - bit №2
    int b = 1;          // сколько бит поменять
 
    for(int i=0; i<sizeof(int)*8; i+=2)
    {
        p=i;
        q=i+1;
        n = swap (n, p, q, b);      
    }
    // n - новое число
    return 0;
}

На входе n = 0xAAAA на выходе 0x5555

0xAAAA = 1010101010101010
0x5555 = 0101010101010101

0x9999 = 1001100110011001
0x6666 = 0110011001100110
→ Ссылка