Fragen? Antworten! Siehe auch: Alternativlos
Wenn Software über Dateien oder das Netzwerk kommuniziert, dann muss man darauf achten, dass die Bytes in der richtigen Reihenfolge abgelegt werden, wenn mehr als eine Plattform an der Kommunikation teilnimmt. Das Problem nennt sich Endianness, ein altes Wortspiel. Man unterscheidet zwischen Big Endian (die wichtigsten Bytes zuerst) und Little Endian (die unwichtigsten Bytes zuerst). Intel ist Little Endian. "Die Anderen" waren mal alle Big Endian, inzwischen ist das häufig umschaltbar.
Typischer Deserialisierungscode sieht dann so aus:
unsigned int foo(const unsigned char* c) { return c[0] + c[1]*0x100 + c[2]*0x10000 + c[3]*0x1000000; } unsigned int bar(const unsigned char* c) { return c[3] + c[2]*0x100 + c[1]*0x10000 + c[0]*0x1000000; }Statt einem Load sind das vier, und lauter Addition und Multiplikation, die jeder aktuelle Compiler in Shifts umwandelt. Die Loads sind aber der teure Teil. gcc erzeugt für beide Funktionen vier Loads und lauter Shifts und Adds.
Nun könnte der Compiler ja theoretisch auch erkennen, dass das als ein einziges Load abzuhandeln ist. Stellt sich raus: clang macht das! clang erzeugt für foo ein 32-bit Load und für bar ein Load und ein bswap (Endianness-Konvertierungs-Instruktion). Das ist mal echt beeindruckend. Ich habe einen Bug bei gcc gefiled, damit die das auch machen.
clang hat inzwischen zu gcc aufgeschlossen was die Qualität des optimierten Codes angeht. Sie setzen gerade zum Überholen an, ist mein Eindruck. Wenn clang noch eine saubere Cross-Compiler-Fähigkeit kriegt, ist gcc so gut wie tot.
Update: Einer der gcc-Leute hat mir geschrieben, dass gcc das für shift und xor schon kann, aber die Addition bringt ihn im Moment in dem Fall durcheinander. Klang als fixen die das jetzt mal eben. Fände ich gut.