Angesichts einer Binärdatei mit 32-Bit-Little-Endian-Felder, die ich analysieren muss, möchte ich Parsing-Code, der korrekt kompiliert unabhängig von Endianness der Maschine, die diesen Code ausführt schreiben. Zur Zeit verwende ichOptimale und portable Konvertierung von Endian in C/C++
uint32_t fromLittleEndian(const char* data){
return uint32_t(data[3]) << (CHAR_BIT*3) |
uint32_t(data[2]) << (CHAR_BIT*2) |
uint32_t(data[1]) << CHAR_BIT |
data[0];
}
dies jedoch eine optimale Montage zu generieren. Auf meinem Rechner g++ -O3 -S
produziert:
_Z16fromLittleEndianPKc:
.LFB4:
.cfi_startproc
movsbl 3(%rdi), %eax
sall $24, %eax
movl %eax, %edx
movsbl 2(%rdi), %eax
sall $16, %eax
orl %edx, %eax
movsbl (%rdi), %edx
orl %edx, %eax
movsbl 1(%rdi), %edx
sall $8, %edx
orl %edx, %eax
ret
.cfi_endproc
, warum dies geschieht? Wie konnte ich es überzeugen optimalen Code zu erzeugen, wenn auf Little-Endian-Maschinen zusammengestellt:
_Z17fromLittleEndian2PKc:
.LFB5:
.cfi_startproc
movl (%rdi), %eax
ret
.cfi_endproc
, die ich durch Kompilieren bekommen haben:
uint32_t fromLittleEndian2(const char* data){
return *reinterpret_cast<const uint32_t*>(data);
}
Da ich weiß, dass meine Maschine Little-Endian, ich Sie wissen, dass die obige Assembly optimal ist, aber es wird fehlschlagen, wenn sie auf einer Big-Endian-Maschine kompiliert wird. Es verletzt auch strikte Aliasing-Regeln, wenn es inlined ist, könnte es UB sogar auf Little-Endian-Maschinen erzeugen. Gibt es einen gültigen Code, der zur optimalen Montage kompiliert wird wenn möglich?
Da ich davon ausgehe, dass meine Funktion viel inline ist, kommt jede Art von Runtime-Endian-Erkennung nicht in Frage. Die einzige Alternative zum Schreiben optimaler C/C++ - Codes besteht darin, die Kompilierzeit-Endianerkennung zu verwenden und template
s oder #define
s zu verwenden, um auf den ineffizienten Code zurückzugreifen, wenn das Zielendian nicht Little-Endian ist. Dies scheint jedoch sehr schwierig portabel zu sein.
Sie können 'reinterpret_cast' nicht zuordnen. Es wird kein Byte neu angeordnet. Wenn Sie den Endian-Byte-Shuffle tanzen müssen, müssen Sie die Band bezahlen. – user4581301
Die Sache ist, dass, wenn meine Compile-Ziel-Plattform Little Endian ist, dann brauche ich keine Byte-Shuffle - Compiler sollte das auch wissen, aber es erzeugt sowieso Byte-Shuffle-Code. –
Thing ist der Compiler weiß nicht, dass Sie Endian spiegeln. Es sieht nur eine Reihe von Schichten und Ors. Wäre aber ein netter Trick. Kann auf der Makefile-Ebene abspielen und die richtige Funktion kompilieren und verknüpfen, aber das wird jegliche Inlining-Funktion beenden. – user4581301