Поменять местами альтернативные байты в целом числе

#c #byte #bit #swap

#c #байт #бит #поменять местами

Вопрос:

Проблема: поменять местами альтернативные байты, как показано ниже:

Ввод: uint8_t buf[4] = {0xab,0xcd,0xef,0xba};

Вывод: 0xcdababef

У меня есть приведенный ниже код для этого, но мне интересно, есть ли какой-нибудь лучший способ сократить код.

 #include <stdint.h>
#define SWAP_16(buf) (((buf amp; 0xFF00) >> 8) | ((buf amp; 0x00FF) << 8))
int main()
{
    unsigned int value;
    int i, j=0;
    uint8_t buf[4] = {0,4,0,0};
    unsigned int mask = 0xFFFF;
    unsigned int tmp_value;
    unsigned int size = 4;

    for (i = size - 1 ;i >= 0; i--) {
        tmp_value |= (buf[j] << 8*i);
        j  ;
    }

    value = SWAP_16((tmp_value amp; (mask << 16)) >> 16) << 16 |
        SWAP_16(tmp_value amp; mask);  
    return 0;
}
  

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

1. Зачем использовать an int ? Просто поменяйте местами байты в массиве….

2. #define SWAPPED(b) { b[1], b[0], b[3], b[2] } uint8_t bswap[4] = SWAPPED(buf); .. ?

3. вы имели 0xcdabbaef в виду, как предполагалось, вывод? Если нет, то неясно, каково ваше условие

4. (для 32-разрядных unsigned int ): value = ((value amp; 0xff00ff00) >> 8) | ((value amp; 0x00ff00ff) << 8);

5. @M.M: это ожидаемый результат, как четко объяснено. Почему вы думаете иначе?

Ответ №1:

Предполагая unsigned int , что это 32 бита, вы можете просто использовать:

 value = ((value amp; 0xff00ff00) >> 8) | ((value amp; 0x00ff00ff) << 8);
  

чтобы поменять местами байты в каждой паре байтов в value . Это похоже на ваш SWAP_16() макрос, за исключением того, что он выполняет обе половины значения одновременно.

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

1. Это не работает для указанного формата ввода uint8_t buf[4] = {0xab,0xcd,0xef,0xba};

2. @M.M Он выполняет замену байтов, он просто не помещает байты массива в unsigned int первый… его код уже сделал это до того, как все равно поменял байты местами (хотя, конечно, есть и другие способы).

3. @user3053970 Или использовать memcpy() which будет копировать в правильном порядке (для перед обменом) на больших конечных машинах… для небольших конечных байтов, таких как x86, вы все равно можете использовать memcpy() , если поменяете местами половинки вместо байтов внутри них, например. value = ((value amp; 0xffff0000) >> 16) | ((value amp; 0x0000ffff) << 16); . Или вы можете использовать объединение, но это будет иметь аналогичные проблемы с порядком следования. Или сдвиньте каждый элемент массива в его конечную позицию при копировании, например. value = (buf[0] << 16) | (buf[1] << 24) | buf[2] | (buf[3] << 8); , вместо копирования, а затем замены … и т.д.

Ответ №2:

 unsigned int forward = 0x12345678;
unsigned int reverse;

unsigned char *f = amp;forward;
unsigned char *r = amp;reverse;

r[0]=f[3];
r[1]=f[2];
r[2]=f[1];
r[3]=f[0];
  

теперь обратным будет 0x78563412

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

1. Разве это не нарушает строгое правило псевдонимов?

2. это неправильно!! Вы неправильно поняли вопрос.

3. @alk нет, символьные типы могут использоваться для чтения и записи других типов

4. в мою защиту у него есть тип в этом вопросе, который все еще существует, так что кто знает, чего он действительно хотел. Технически из его вопроса он хотел, чтобы 3 байта были перемещены, а один дублирован.

Ответ №3:

Вот один из способов:

 #include <stdio.h>
#include <stdint.h>

int main(void)
{
    uint8_t buf[4] = {0xab,0xcd,0xef,0xba};

    unsigned int out = buf[1] * 0x1000000u   buf[0] * 0x10000u   buf[3] * 0x100u   buf[2];
    printf("%xn", out);
}
  

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

1. Понимаете ли вы систему значений места, например, в десятичных 123 означает 100 20 3 . это то же самое в шестнадцатеричном формате, 0x123 означает 0x100 0x20 0x3. В этом случае мы обрабатываем две цифры одновременно: 0x12345678 означает 0x12000000 0x340000 0x5600 0x78.

Ответ №4:

Из вашего вопроса не сразу понятно, не вариант ли это, но вы могли бы просто поменять местами байты в массиве, если знаете, что размер не изменится:

 #include <stdio.h>
#include <stdint.h>
#define SWAPPED(b) { b[1], b[0], b[3], b[2] }
#define PRINT(b) printf("0x0%xn", *((uint32_t*)b));

int main()
{
    uint8_t buf[4] = {8,4,6,1};
    uint8_t swapped[4] = SWAPPED(buf);
    PRINT(buf);
    PRINT(swapped);
    return 0;
}
  

Вывод для этого на моей машине:

 0x01060408
0x06010804
  

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

Надеюсь, это поможет.

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

1. хорошая хитрая логика. Откуда вы взяли эту идею :)?

2. @user3053970, я уже некоторое время занимаюсь C 🙂

3. Обратите внимание, что это связано с проблемой сглаживания

4. @user3053970, что вы имеете в виду, что это не дает результата? Это ожидаемый результат, учитывая, что вы печатаете.

5. @txtechhelp: внимательно посмотрите на результат

Ответ №5:

Используйте объединение

 #include <stdint.h>


#define SWAP_VAR(T, v1, v2) do { 
  T v = (v1); 
  (v1) = (v2); 
  (v2) = v; 
} while (0);

union U32
{
  uint32_t u;
  unsigned char a[4];
};

uint32_t swap32(uint32_t u)
{
  union U32 u32 = {u};

  SWAP_VAR(unsigned char, u32.a[0], u32.a[1]);
  SWAP_VAR(unsigned char, u32.a[2], u32.a[3]);

  return u32.u;
}
  

Используйте это так:

 #include <stdint.h>

uint32_t swap32(uint32_t u);


int main(void)
{
  uint32_t u = 0x12345678;
  u = swap32(u);
}
  

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

1. вы запускали эту программу?

2. a[2] = c; должно быть a[3] = c;

3. Да, да, исправлена эта небрежность … извините! @M.M

4. @user3053970: Справедливо, но концепция была ясна, не так ли? 😉

Ответ №6:

 unsigned int n = ((unsigned int)buf[0] << 16) |
                 ((unsigned int)buf[1] << 24) |
                 ((unsigned int)buf[2] <<  0) |
                 ((unsigned int)buf[3] <<  8);