Endianess berücksichtigen (16 Bit)



  • Ich möchte(muss) 16 Bit Wörter über TCP versenden. Byteorder soll Big Endian sein. Welche Variante würdet Ihr bevorzugen:

    #ifdef _WIN32
    #include <winsock2.h>
    #else
    #include <arpa/inet.h>
    #endif
    
    uint16_t getBigEndianInt(uint16_t val)
    {
        return htons(val);
    }
    
    #include <cstdint>
    
    bool isLittleEndian()
    {
        static const int16_t i = 1;
        return reinterpret_cast<const int8_t&>(i) == 1;
    }
    
    inline void swapEndian(uint16_t& x)
    {
        x = (x>>8) | (x<<8);
    }
    
    uint16_t getBigEndianInt(uint16_t val)
    {
        if(isLittleEndian()){
            swapEndian(val);
        }
        return val;
    }
    

    ...oder ganz anders?

    Danke für Eure Hilfe im Voraus! 🙂



  • Ich würde Messungen machen was schneller ist. Eventuell würde ich die "isLittleEndian" Ausgabe bei Programmstart berechnen und in nen globalen bool schreiben, dann brauch der PC das nicht bei jedem Aufruf erneut berechnen.
    Überhaupt sieht mir die "isLittleEndian" Funktion relativ gewagt aus, hast du die mal auf beiden Architekturen überprüft?



  • .. ganz anders.

    Zunächst einmal gibst Du etwas via TCP aus. In C++ ist die IO-Library für Ein- und Ausgaben zuständig; d.h. Streams und Streambuffer.
    Das Umwandeln eines beliebigen Typs (hier ein uint16_t) in eine Folge von Zeichen ist eindeutig die Aufgabe eines Streams.
    Wobei der std::ostream hier nicht taugt, da dieser Zahlen in lesbaren Text und nicht binär ausgibt. Folglich wäre es angebracht, einen eigenen Stream zu bauen (z.B. obinstream), der von std::basic_ios< char > abgeleitet ist. std::basic_ios<> deshalb, weil hier schon die Fehlerflags und der Zugriff auf den std::streambuf enthalten ist.

    Der Code könnte dann etwa so aussehen:

    class obinstream : public std::basic_ios< char >
    {
        typedef std::basic_ios< char > base_type;
    public:
        obinstream( std::streambuf* sb )
            : base_type( sb )
        {}
        obinstream& operator<<( uint16_t x )
        {
            if( !fail() )
            {
                // schreibt ein uint16 im Big Endian Format
                std::streambuf* sb = rdbuf();
                if( sb->sputc( static_cast< unsigned char >(x >> 8) ) == traits_type::eof() 
                    || sb->sputc( static_cast< unsigned char >(x) ) == traits_type::eof() )
                    setstate( std::ios_base::failbit | std::ios_base::eofbit );
            }
            return *this;
        }
    };
    

    Gruß
    Werner



  • Ich setzte so etwas meist manuell zusammen.

    #include <climits>
    
    #if CHAR_BIT != 8
    #error "weird platform: CHAR_BIT != 8"
    #endif
    
    inline unsigned readU16be(const void* in)
    {
      const unsigned char* p = static_cast<const unsigned char*>(in);
      return (unsigned(p[0])<<8) | p[1];
    }
    
    inline void writeU16be(void* out, unsigned value)
    {
      unsigned char* p = static_cast<unsigned char*>(in);
      p[0] = (value >> 8);
      p[1] = value;
    }
    

    (ungetestet)

    Und das mit der CHAR_BIT==8 Bedingung ist keine Einschränkung, um die man sich normalerweise Sorgen machen muss.



  • Vielen Dank Werner Salomon! 👍 Das ist sehr hilfreich. An eine Streamlösung habe ich auch gedacht, wobei das für mich eine ordenltiche Herausforderung ist - dein Beispiel hilft da ungemein.

    Du gehst aber davon aus, dass das ganze auf einem Little-Endian System läuft, nicht wahr? Würdest Du keine Überprüfung einbauen um portabel zu bleiben?

    Oder ist das Ergebnis des Shift-Operators unabhängig von der Byteorder des Systems? Dann wäre es ja portabel.

    RedPuma schrieb:

    Überhaupt sieht mir die "isLittleEndian" Funktion relativ gewagt aus, hast du die mal auf beiden Architekturen überprüft?

    Nein, habe ich nicht getestet sondern einfach von http://stackoverflow.com übernommen. Nur unsigned char habe ich gegen uint8_t ausgetauscht um auch 8Bit zu gewährleisten. Ich habe leider nur PC-Systeme und dafür programmiere ich eigentlich auch nur (Windows). Nur wollte ich mir ein portablen Programmier-Stil angewöhnen. Wer weiß was kommt...



  • Roger Wilco schrieb:

    Du gehst aber davon aus, dass das ganze auf einem Little-Endian System läuft, nicht wahr?

    Nein

    Roger Wilco schrieb:

    Oder ist das Ergebnis des Shift-Operators unabhängig von der Byteorder des Systems? Dann wäre es ja portabel.

    davon gehe ich aus.



  • Das habe ich gerade hier auch gelsen: http://stackoverflow.com/questions/1041554/bitwise-operators-and-endianness

    Vielen Dank! 🙂


Anmelden zum Antworten