Endianness

Im Netz wird Big-Endian gesprochen. Daran muss man denken, wenn man Strukturen über TCP/IP an andere Hosts senden will. Der folgende Code wird deshalb nicht funktionieren, wenn er auf einer Intel-Maschine unter Linux ausgeführt wird. An dieser Stelle noch die Anmerkung: Java hat intern immer Big-Endian-Repräsentation

struct Messwert
{
    long long nanoseconds_ad;
    double wert;
    Messwert(int z, double w) : nanoseconds_ad(z), wert(w) {}
    Messwert(const Messert& other)
    :nanoseconds_ad(other.nanoseconds_ad)
    ,wert(other.wert) {}
};

Messert m(42, 1234.5);
send(socket, &m, sizeof(m))

Um die Endianness für seine Maschine zu prüfen, kann man wie im folgenden Code gezeigt wird, eine Integer-Variable mit dem Wert 1 auch als char-Pointer interpretieren. Bei Little-Endian steht an der ersten Position in diesem Zeiger das niedrigwertigste Bit. Bei Big-Endian ist es entsprechend anders herum.

Die Zahl 75 binär dargestellt ist 0100 1011. Je nach Endianness ist die Darstellung im Speicher unterschiedlich:

  • Little Endian: 1101 0010
  • Big Endian: 0100 1011

Für 64-Bit-Integer benötigt man nicht standardisierte host-to-net (und vice-versa) Konverter. Mit endian.h stellt uns Linux zum Glück die entsprechenden Konverter zur Verfügung.

#include <stdio.h>
#include <endian.h>
int
main(int, char**)
{
    // Endian-Test
    int n = 1;
    if (*(char*)&n == 1)
        fprintf(stdout, "little\n");
    else
        fprintf(stdout, "big\n");

    // Konverter Tests
    unsigned long long ll = 1234LL;
    fprintf(stdout, "to_net(%llu) = %llu\n", ll, htobe64(ll));
    fprintf(stdout, "to_host(%llu) = %llu\n", htobe64(ll), be64toh(htobe64(ll)));

    // Wegen inv(inv(x)) = x würde auch ein einziger Konverter genügen
    fprintf(stdout, "to_net(to_net(%llu)) = %llu\n", ll, htobe64(htobe64(ll)));
    fprintf(stdout, "to_host(to_host(%llu)) = %llu\n", ll, be64toh(be64toh(ll)));
}

Mit diesem Wissen können wir also die Messdaten korrekt übertragen

struct Messwert
{
    long long nanoseconds_ad;
    double wert;
    Messert() : nanoseconds_ad(0LL), wert(0.0) {}
    Messwert(long long z, double w) : nanoseconds_ad(z), wert(w) {}
    void pack(Messwert& target)
    {
        target.nanoseconds_ad = htobe64(nanoseconds_ad);
        target.wert = wert;
    }
};

Messwert m(42LL, 1234.5);
Messwert p(m);
p.pack();
send(socket, &p, sizeof(p))