signed char / unsigned char / char



  • 314159265358979 schrieb:

    TyRoXx schrieb:

    Man könnte die Bytes auch direkt in umgekehrter Reihenfolge in die Ausgabe schreiben.

    Was sich super auf die Datenrate auswirkt.

    Den verstehe ich jetzt nicht.

    Ausgabe ist hier der Sendepuffer. Das was bei SFML wohl sf::Packet heißt.



  • Puffer != direkt 😉
    Aber ich verstehe, was du meinst. Kleines Missverständnis.



  • Mit direkt wollte ich ausdrücken, dass keine Hilfsvariable gleichen Typs genommen wird, um die Bytes umzudrehen. Da die Bytes ohnehin in den Puffer kopiert werden müssen, kann man die Konvertierung auch dabei erledigen.



  • TyRoXx schrieb:

    Mit direkt wollte ich ausdrücken, dass keine Hilfsvariable gleichen Typs genommen wird, um die Bytes umzudrehen. Da die Bytes ohnehin in den Puffer kopiert werden müssen, kann man die Konvertierung auch dabei erledigen.

    Schon verstanden 😉
    Allerdings denke ich, dass der Compiler das sowieso dahingehend optimieren wird.



  • 314159265358979 schrieb:

    Ich verwende diese Funktionen zum Konvertieren nach Big Endian auch für floats und doubles, da ich Big Endian senden muss.

    Warum musst du das? Wir könnten doch auch in little-endian senden.
    Afaik haben x86 little endian.
    Ich weiß zwar das die "Host-Network-Order" Big-Endian ist, aber wieso das so ist und warum man sich daran halten "muss" verstehe ich nicht.



  • Weil der Server, zu dem ich sende, nunmal Big-Endian liest. Da muss ich nunmal umwandeln. Java ftw!



  • Ok, solche Probleme hab ich nicht 🙂

    Ich wollte das dann ungefähr so einsetzen:

    bool isLittleEndian() 
    { 
        int i = 1; 
        return *reinterpret_cast<char*>(&i) == 1; 
    }
    
    template <typename T> 
    void swapEndianess(T& t) 
    { 
        char* data = reinterpret_cast<char*>(&t); 
        std::reverse(data, data + sizeof(T)); 
    }
    
    template <typename T> 
    void toBigEndian(T& t)
    {
        if(isLittleEndian())
    	{
    		swapEndianess(t);
    	}
    }
    
    template <typename T> 
    void fromBigEndian(T& t)
    {
    	if(isLittleEndian())
    	{
    		swapEndianess(t);
    	}
    }
    

    Mir fällt gerade auf das
    toBigEndian == fromBigEndian.



  • 314159265358979 schrieb:

    Ich verwende diese Funktionen zum Konvertieren nach Big Endian auch für floats und doubles, da ich Big Endian senden muss.

    Bist du dir wirklich sicher, dass float und double auch von endianess betroffen sind?

    SFML macht da keine konvertierung.
    QT auch nicht, wenn ich das richtig verstehe:
    http://doc.qt.nokia.com/latest/qtendian.html

    T qFromBigEndian ( const uchar * src )

    Reads a big-endian number from memory location src and returns the number in the host byte order representation. On CPU architectures where the host byte order is little-endian (such as x86) this will swap the byte order; otherwise it will just read from src.

    Note: Template type T can either be a qint16, qint32 or qint64. Other types of integers, e.g., qlong, are not applicable.

    Also scheints für float/double nicht zu funktionieren, was dafür spricht, dass es dabei nicht nötig ist.
    Weiß da wer mehr?

    Und QT hat sowohl fromBigEndian als auch toBigEndian, bei mir hatte beides den selben code, kann das so stimmen?



  • Ich sende zu einem Java-Server, der verwendet Big Endian. Wie alles in Java.



  • Ich weiß, es ging mir darum, ob es das Endianess-Problem nur für Ganzzahl-Typen, oder auch für Fließpunktzahlen gibt.
    Habe dazu aber gerade noch das hier gefunden:
    http://stackoverflow.com/questions/2782725/converting-float-values-from-big-endian-to-little-endian/2782742#2782742
    Also scheint es für float/double doch auch nötig zu sein das zu beachten.

    Edit:
    Auf einem Little-Endian-Rechner wird java aber doch wohl nur bei IO in big-endian umrechnen und nicht immer damit rechnen, oder?
    Ansonsten würde das doch totalen overhead erzeugen.

    Und was war mit toBigEndian/fromBigEndian identisch, stimmt das so?



  • 314159265358979 schrieb:

    Ich sende zu einem Java-Server, der verwendet Big Endian. Wie alles in Java.

    Java selbst (core language) hat soweit ich weiss kein Konzept von Endianness. Diverse Serialisierungs-Klassen definieren dann welche Endianness verwendet wird.
    Und JNI wird, schätze ich mal, die selbe Endianness verwenden wie die CPU bzw. das OS das die VM hostet. Wäre ziemlich doof wenns anders wäre.



  • Q schrieb:

    Also scheints für float/double nicht zu funktionieren, was dafür spricht, dass es dabei nicht nötig ist.

    Das Format von floats und doubles im Speicher ist durch einen IEEE Standard definiert, und unabhängig von der Integer-Endianness der CPU/Plattform.
    Kurz: da muss man nix dran drehen, das passt immer.

    Das einzige was Probleme machen könnte, ist, wenn eine Partei z.B. "long double" als 64 Bit versteht, und die andere als 80 Bit.
    Oder wenn eine Partei nicht-IEEE-konforme Floating Point Zahlen verwendet.

    Und QT hat sowohl fromBigEndian als auch toBigEndian, bei mir hatte beides den selben code, kann das so stimmen?

    Naja...
    Eine Funktion die 1-2-3-4 in 4-3-2-1 verwandelt, wird auch 4-3-2-1 wieder zurück zu 1-2-3-4 verwandeln.

    Wenn das System big endian ist, dann machen sowohl fromBigEndian() als auch toBigEndian() genau gar nix.
    Wenn das System little endian ist, dann drehen beide Funktionen einfach die Reihenfolge der Bytes um.

    In beiden Fällen sind die Funktionen also identisch.

    Unterschiedlich könnten sie nur sein, wenn ein System weder little endian noch big endian ist. z.B. wenn es 2-3-4-1 oder sowas verwendet. Ich wüsste allerdings von keinem solchen System.

    Ich *schätze* Qt bietet einfach nur deswegen zwei getrennte Funktionen an, damit der Code besser lesbar wird (vorausgesetzt man ruft immer die Funktion auf, die an der Stelle logisch passend ist).



  • 314159265358979 schrieb:

    Ich sende zu einem Java-Server, der verwendet Big Endian. Wie alles in Java.

    Quatsch. Du hast gar nicht die Möglichkeit zu überprüfen, wie ein int im Speicher liegt, weil es sowas wie reinterpret_cast<unsigned char*>(&intvariable) oder memcpy ins char-array gar nicht gibt. 😉

    Und bei der ByteBuffer-Klasse kann man die ByteOrder setzten, in der Ganzzahlen abgelegt/gelesen werden sollen.



  • Der Server schreibt mit einem DataOutputStream bzw liest mit einem DataInputStream. Und ich bin mir sicher, dass da im NBO geschrieben wird, also Big Endian.



  • 314159265358979 schrieb:

    Der Server schreibt mit einem DataOutputStream bzw liest mit einem DataInputStream. Und ich bin mir sicher, dass da im NBO geschrieben wird, also Big Endian.

    kk hat es schon gesagt: Nimm ByteBuffer. Da kannst Du die zu verwendene Endianess setzen. Du packst typisiertes Zeugs rein, und holst die passende Bytesequenz in der gewünschten Endianess wieder raus. Fertig.



  • Der Server ist nicht von mir geschrieben worden, ich werde da sicher nichts ändern. 😉



  • 314159265358979 schrieb:

    camper schrieb:

    Im Prinzip ist das Ganze in dieser Form ohnehin Unfug: Ein T ist im Allgemeinen nach einem swap kein T mehr.

    Da das nur mit PODs so funktioniert, ist er das schon. 😉
    Wobei ich die Typen, die ich da durchgejagt habe, auch nicht mehr anrühren würde. Ich verwende diese Funktionen zum Konvertieren nach Big Endian auch für floats und doubles, da ich Big Endian senden muss.

    Es wäre aber trotzdem besser, in ein uint8_t[sizeof(T)] oder ähnliches zu kopieren. Schlussendlich muss das eh irgendwo gemacht werden.


Anmelden zum Antworten