/ / Jaki jest najszybszy sposób przełączania endianności podczas odczytu z pliku za pomocą C ++? - c ++, wydajność, plik, endianness

Jaki jest najszybszy sposób zmiany endianness podczas czytania z pliku z C ++? - c ++, wydajność, plik, endianness

Dostałem plik binarny do przeczytania, któryprzechowuje sekwencję nieprzetworzonych wartości. Dla uproszczenia załóżmy, że „są niepodzielnymi wartościami integralnymi, albo 4-bajtowymi, albo 8-bajtowymi. Niestety dla mnie kolejność bajtów dla tych wartości jest niezgodna z endiannością mojego procesora (mała vs duża lub odwrotnie; nieważne o dziwnej endianności PDF itp.); i chcę, aby te dane były w pamięci z właściwą endiannością.

Jaki jest najszybszy sposób, aby to zrobić, biorąc pod uwagę fakt, że czytam dane z pliku? Jeśli nie warto wykorzystywać tego faktu, proszę wyjaśnić, dlaczego tak jest.

Odpowiedzi:

2 dla odpowiedzi № 1

Biorąc pod uwagę fakt, że czytasz dane z pliku, sposób przełączania endianności będzie miał niewielki wpływ na środowisko wykonawcze, w porównaniu z tym, co robi plik-IO.

Istotną różnicą może być sposóbczytasz dane. Próba odczytania bajtów poza kolejnością nie byłaby dobrym pomysłem. Po prostu odczytaj bajty w kolejności, a następnie przełącz endianność. To oddziela odczyt i wymianę bajtów.

Co ja Zwykle z kodu zamiany bajtów chce, a na pewno w przypadku odczytu pliku, że działa dla każdej endianności i nie zależy od instrukcji specyficznych dla architektury.

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

Działa to niezależnie od tego, czy rdzenny jest duży, mały lub jeden z odmian środkowego endianu.

Oczywiście, podnieść już je zaimplementował, więc nie ma potrzeby ponownego wdrażania. Są też ntoh? rodzina funkcji udostępnianych zarówno przez POSIX, jak i bibliotekę Windows C, która może być używana do konwertowania big endian na / z native.


1 dla odpowiedzi nr 2

Nie najszybszy, ale przenośny sposób polegałby na odczytaniu pliku do tablicy (niepodpisanych) int, aliasu tablicy int do postaci char (dozwolonej według ścisłej reguły aliasingu) i zamianie bajtów w pamięci.

W pełni przenośny sposób:

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;
}
}

Ale jeśli nie potrzebujesz przenośności, niektóre systemy oferują funkcje wymiany. Na przykład systemy BSD mają bswap16, bswap32 i bswap64 zamieniać bajt w uint16_t, uint32_t i uint_64_t odpowiednio. Bez wątpienia równoważne funkcje istnieją w światach Microsoft lub GNU-Linux.

Alternatywnie, jeśli wiesz, że plik jest w sieć order (big endian), a twój procesor nie jest, możesz użyć ntohs i ntohl funkcje odpowiednio uint16_t i uint32_t.

Uwaga (według komentarza AndrewHenle'a): niezależnie od endianności hosta, ntohs i ntohl zawsze może być użyty - po prostu są operacjami typu big-endian