Eu tenho fornecido um arquivo binário para ler, quecontém uma sequência de valores brutos. Por uma questão de simplicidade, suponha que eles "não tenham valores integrais, de 4 bytes ou 8 bytes. Infelizmente para mim, a ordem de bytes para esses valores é incompatível com o endianness de meu processador (pouco contra grande ou vice-versa); não se preocupe com a estranheza do PDF-endianness etc.); e quero esses dados na memória com o endianness adequado.
Qual é a maneira mais rápida de fazer isso, considerando o fato de que estou lendo os dados de um arquivo? Se não vale a pena explorar este fato, por favor, explique por que isso é.
Respostas:
2 para resposta № 1Considerando o fato de que você está lendo os dados de um arquivo, a forma como você alterna o endianness terá um efeito insignificante no tempo de execução, comparado com o que o file-IO faz.
O que poderia fazer uma diferença significativa é comovocê lê os dados. Tentar ler os bytes fora de ordem não seria uma boa ideia. Simplesmente leia os bytes em ordem e mude o endianness depois. Isso separa a leitura e a troca de bytes.
o que Eu Quer o código de troca de byte normalmente e, certamente, em um caso de leitura de um arquivo, é que ele funciona para qualquer fim de vida e não depende de instruções específicas de arquitetura.
char* buf = read(); // let buf be a pointer to the read buffer
uint32_t v;
// little to native
v = 0;
for(unsigned i = 0; i < sizeof v; i++)
v |= buf[i] << CHAR_BIT * i;
// big to native
v = 0;
for(unsigned i = 0; i < sizeof v; i++)
v |= buf[i] << CHAR_BIT * (sizeof v - i);
Isso funciona se o nativo é grande, pequeno ou um dos tipos de endívia média.
Claro, impulso já implementou estes para você, então não há necessidade de re-implementar. Além disso, existem os ntoh?
família de funções fornecidas pelo POSIX e pela biblioteca windows C, que pode ser usada para converter big endian de / para nativo.
1 para resposta № 2
Não é o mais rápido, mas uma maneira portátil seria ler o arquivo em uma matriz int (não assinada), alias a matriz int a uma char (permitida por regra de aliasing estrita) e trocar bytes na memória.
Maneira totalmente portátil:
swapints(unsigned int *arr, size_t l) {
unsigned int cur;
char *ix;
for (size_t i=0; i<l; i++) {
int cur;
char *dest = static_cast<char *>(&cur) + sizeof(int);
char *src = static_cast<char *>(&(arr[i]));
for(int j=0; j<sizeof(int); j++) *(--dest) = *(src++);
arr[i] = cur;
}
}
Mas se você não precisa de portabilidade, alguns sistemas oferecem funções de troca. Por exemplo, os sistemas BSD bswap16
, bswap32
e bswap64
trocar byte em uint16_t
, uint32_t
e uint_64_t
respectivamente. Sem dúvida existem funções equivalentes nos mundos Microsoft ou GNU-Linux.
Como alternativa, se você sabe que o arquivo está em rede ordem (big endian) e seu processador não é, você pode usar o ntohs
e ntohl
funções para respectivamente uint16_t
e uint32_t
.
Comentário (de acordo com Andrew Henle): seja qual for a host endianness, ntohs
e ntohl
sempre pode ser usado - simplesmente eles não são operados em sistemas big-endian