little endian, big endian



  • Ich arbeite gerade daran, einen digitalen Synthesizer mittels Mikrocontrollerschaltung zu bauen. Die Audioalgorithmen die ich dafür brauche probiere ich in C aus und bin gerade erst am Anfang.
    Ich will zunächst ein Programm schreiben, das verschiedene Wellenformen, Filterungen etc. in ein WAV-File schreibt. In einer Beschreibung des WAV-Formats heißt es, dass die einzelnen Daten (zumeist DWORDs) im little-endian Modus in den Dateien stehen. Also soll das niederwertigste Byte als erstes stehen. Also habe ich mal angetestet, wie C ein 4 Byte Integer in eine Datei schreibt. Der Integer hat einen Wert von 0xAABBCCDD. Da ich im Hex-Editor ein aa bb cc dd sehe, scheint es wohl als big-endian geschrieben worden zu sein.
    Für meine WAV-Files ist das also so unbrauchbar.

    Kann ich irgendwie erreichen, dass Variablen grundsätzlich little-endian behandelt werden? Per Compilerdirektive? Oder wie kann ich am einfachsten die Bytes einer Variable umdrehen, bevor ich sie in die Datei schreibe?



  • Hugoderwolf schrieb:

    Also habe ich mal angetestet, wie C ein 4 Byte Integer in eine Datei schreibt. Der Integer hat einen Wert von 0xAABBCCDD. Da ich im Hex-Editor ein aa bb cc dd sehe, scheint es wohl als big-endian geschrieben worden zu sein.

    Noch schlimmer: Wie genau ein Integer im Speicher abgelegt wird, ist vollkommen undefiniert.

    Kann ich irgendwie erreichen, dass Variablen grundsätzlich little-endian behandelt werden? Per Compilerdirektive? Oder wie kann ich am einfachsten die Bytes einer Variable umdrehen, bevor ich sie in die Datei schreibe?

    Schau Dir mal htonl() bzw. ntohl() an.



  • SG1 schrieb:

    Noch schlimmer: Wie genau ein Integer im Speicher abgelegt wird, ist vollkommen undefiniert.

    Was genau heißt das? Wäre ja für meine Zwecke recht wichtig, weil ich ja mit write() ab der Startadresse der Variable die länge von int in eine Datei schreibe. Oder wie?

    System ist übrigens MacOS X.3.2, wohl etwas exotisch hier. 😉

    Edit: Daran muss es liegen:

    Besteht ein Wert aus mehreren Bytes, wird auf 80x86 Prozessoren das niederwertige Byte   vorangestellt   (Least Significant Byte first), während man sich im Internet auf die umgekehrte Byteordnung geeinigt hat (Most Significant Byte first).

    P.S.: Schönes Forum hier übrigens!



  • OK, die von dir genannten Funktionen tun nix. Folgender Versuchsaufbau:

    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #define TESTFILE "/testfile"
    
    void writefile(void) {
    	int fd;
    	unsigned long int test = 0xAABBCCDD;
    
    	fd = creat(TESTFILE, 0644);
    	write(fd, &test, sizeof(test));
    	write(fd, &htonl(test), sizeof(test));
    	write(fd, &ntohl(test), sizeof(test));
    	close(fd);
    }
    
    int main (int argc, const char * argv[]) {
    	writefile();
    	return 0;
    }
    

    In der Datei steht anschließend in Hex "aa bb cc dd aa bb cc dd aa bb cc dd".



  • Hugoderwolf schrieb:

    SG1 schrieb:

    Noch schlimmer: Wie genau ein Integer im Speicher abgelegt wird, ist vollkommen undefiniert.

    Was genau heißt das?

    Theoretisch heisst das, dass sich die Byte-Order mit dem Sonnenstand aendern kann. Praktisch wohl nur, wenn Du versuchst, das Programm auf eine andere Architektur zu portieren.

    OK, die von dir genannten Funktionen tun nix.

    Nicht ganz. Sie wandeln einen Integer in die "network byte order" um (bzw. umgekehrt). "network byte order" ist die Reihenfolge, die im Internet verwendet wird. Und der Mac verwendet anscheinend schon die fuers Internet richtige Reihenfolge, also sind das _auf Deiner Plattform_ wirklich NOPs - aber nicht ueberall. Aber fuer Deine Anwendung ist es wohl leider die falsche...

    Also anders:

    uint32_t foo = ((bar & 0xFF000000) >> 24) | ((bar & 0xFF0000) >> 16) | ((bar & 0xFF00) >> 8) | (bar & 0xFF)
    

    dreht die Reihenfolge der Bytes um.



  • SG1 schrieb:

    Nicht ganz. Sie wandeln einen Integer in die "network byte order" um (bzw. umgekehrt). "network byte order" ist die Reihenfolge, die im Internet verwendet wird. Und der Mac verwendet anscheinend schon die fuers Internet richtige Reihenfolge, also sind das _auf Deiner Plattform_ wirklich NOPs - aber nicht ueberall. Aber fuer Deine Anwendung ist es wohl leider die falsche...

    Naja, hatte mich wohl seltsam ausgedrückt. Eigentlich meinte ich "Die Funktionen nützen bei mir nichts."
    Na gut, portieren muss ich es nicht, aber dann müsste ich erstmal htonl() aufrufen und dann umdrehen, um sicher zu gehen, dass die Byte Order umgekehrt ist?
    Angenommen, ich kompiliere das Prog auf 'ner x86-Maschine, würde ich gedrehte Bytes in der Datei haben?



  • SG1 schrieb:

    Also anders:

    uint32_t foo = ((bar & 0xFF000000) >> 24) | ((bar & 0xFF0000) >> 16) | ((bar & 0xFF00) >> 8) | (bar & 0xFF)
    

    dreht die Reihenfolge der Bytes um.

    Da hast du dich wohl vertan, das funktioniert so nicht.

    So geht's:

    unsigned long int foo = ((bar & 0xFF000000) >> 24) | ((bar & 0xFF0000) >> 8) | ((bar & 0xFF00) << 8) | ((bar & 0xFF) << 24);
    

    Bei deiner Variante wird quasi jedes Byte nach ganz hinten geschoben. 😉



  • Hugoderwolf schrieb:

    Da hast du dich wohl vertan, das funktioniert so nicht.

    Jo, ist mir dann auch eingefallen, als ich im Bett lag. Ich sollte so spaet nichtmehr posten. Immerhin ist Dir der Fehler aufgefallen.


Anmelden zum Antworten