#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);