Обмен битов и указатель

у меня есть struct, который состоит из нескольких 32-битных элементов. Я применил #pragma pack (4)поэтому следующая структура является линейной и выровненной.

struct
{
int a; // 4 bytes
int b; // 4 bytes
int c; // 4 bytes
} mystruct; // total 16 bytes

Как я могу поменять местами каждый из этих элементов (little -> big endian)?

Метод void swap(void* a, int b);, с a указатель на структуру и b целое число, дающее размер структуры.

Например :

void swap(void* a, int b)
{
//FIXME !
for (int i = 0; i < b; i+= 32)
{
a = (a & 0x0000FFFF) << 16 | (a & 0xFFFF0000) >> 16;
a = (a & 0x00FF00FF) << 8 | (a & 0xFF00FF00) >> 8;
a += 32;
}
}

2

Решение

Вы можете поменять два байта без использования временного:

void byteswap( unsigned char & a, unsigned char & b )
{
a ^= b;
b ^= a;
a ^= b;
}

Теперь давайте применим его к числам переменной длины

template< typename T >
void endianSwap( T & t )
{
unsigned char * first = reinterpret_cast< unsigned char * >( &t );
unsigned char * last = first + sizeof(T) - 1;
while( first < last )
{
byteswap( *first, *last );
++first;
--last;
}
}

Для вашей структуры вы можете:

void endianSwap( mystruct & s )
{
endianSwap( s.a );
endianSwap( s.b );
endianSwap( s.c );
}

Конечно, в качестве альтернативы endianSwap с использованием byteswap, мы могли бы просто использовать std :: reverse.

template<typename T> endianSwap( T& t )
{
unsigned char * begin = reinterpret_cast<unsigned char *>(&t);
unsigned char * end = begin + sizeof( T );
std::reverse( begin, end );
}
4

Другие решения

Вот возможное исправление для вашей рутины

void swap(void* a, int b)
{
for (int i = 0; i < b; i += 4)
{
int* p = (char*)a + i;
*p = (*p & 0x0000FFFF) << 16 | (*p & 0xFFFF0000) >> 16;
*p = (*p & 0x00FF00FF) << 8 | (*p & 0xFF00FF00) >> 8;
}
}

Надеюсь, не проверено, но немного ближе к исправлению.

1

Если вы работаете на машине с * nix. Есть полезные функции, которые могут сделать это:

#include <arpa/inet.h>
uint32_t htonl(uint32_t hostint32);   // from host to network
// means little to big if your machine is x86
0

Я предполагаю, что под little-> big endian вы имеете в виду изменение порядка байтов в каждом 4-байтовом элементе. Я также предполагаю, чтоa нулевой указатель на структуру «вы имеете в виду»a указатель на структуру «.
В вашем коде есть несколько ошибок. Попробуй это:

void swap(void* a, int b)
{
for (int *pInt = (int *)a; pInt < ((char *)a + b); pInt++)
{
*pInt = (*pInt & 0x0000FFFF) << 16 | (*pInt  & 0xFFFF0000) >> 16;
*pInt = (*pInt & 0x00FF00FF) << 8 | (*pInt & 0xFF00FF00) >> 8;
}
}
0
void swap(void* A, int b)
{
//FIXME !
int *c = (int*)A; // have to cast to an existing type. 'void' doesnt exist
for (int i = 0; i < b; i+=4)  // we are flipping 4 bytes at a time
{
unsigned int a=*c;  // read the content, not the address
// have to have unsigned, otherwise (a&0xff00ff00)>>8 extends the sign bit
a = (a & 0x0000FFFF) << 16 | (a & 0xFFFF0000) >> 16;
a = (a & 0x00FF00FF) << 8 | (a & 0xFF00FF00) >> 8;
*c++= a;  // write back the content
}
}

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

void swap(char *d, char *s, int N) { for (i=0;i<N;i++) d[i^3]=*s++;}

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector