у меня есть 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;
}
}
Вы можете поменять два байта без использования временного:
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 );
}
Вот возможное исправление для вашей рутины
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;
}
}
Надеюсь, не проверено, но немного ближе к исправлению.
Если вы работаете на машине с * nix. Есть полезные функции, которые могут сделать это:
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostint32); // from host to network
// means little to big if your machine is x86
Я предполагаю, что под 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;
}
}
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++;}