signed char / unsigned char / char
-
SFML ist an dieser Stelle einfach fehlerhaft (und nicht nur da). Zum Beispiel wird wahrscheinlich auch
long
nicht funktionieren, weil nurint
überladen ist.long double
undlong long
(nicht Standard, können aber die meisten Compiler) fehlen,w/char/_t *
ist unlogisch, das Verhalten fürbool
ist unklar (denn die Größe vonbool
ist Compiler-abhängig).
Außerdem kann man nicht angeben, wie die String-Länge serialisiert werden soll. Eine Beschränkung der Länge auf genau 32 Bit ist unnötig und Platzverschwendung.
In einer vernünftigen Bibliothek würde man die Operatoren für alle möglichen Typen überladen und nicht diese schwachsinnigentypedef
s verwenden. Portierbaretypedef
s für den Benutzer gibts in Boost oder<cstdint>
.
-
hustbaer schrieb:
Oder du kopierst die Daten einfach direkt aus dem Paket raus. Mit sf::Packet::GetData() kommst du ja an die Daten ran. Wenn das sf::Packet ausser dem String nichts anderes enthält, dann beginnen die Nutzdaten ja immer ab sf::Packet::GetData() + sizeof(int). -> easy
Es enthält leider noch was anderes... Und den ReadPointer kann ich ohne Modifikationen an SFML nicht auslesen.
hustbaer schrieb:
Oder du änderst dein Programm, so dass die Länge gleich gar nicht nochmal redundant mitgeschickt wird, da SFML das sowieso übernimmt. Mit sf::Packet::GetDataSize() kannst du die Länge dann abfragen.
Ich benutze sf::Packet nur zum umwandeln von daten <-> byte/char, das verschicken mache ich mit boost::asio, also wird die länge nicht von selbst mitgeschickt, was bei UDP auch unnötig wäre, weil das afaik schon vom UDP-Protokoll gemacht wird.
hustbaer schrieb:
Oder, falls die Pakete doch noch andere Dinge enthalten, änderst du sf::Packet entsprechend ab, so dass du den Read-Pointer auslesen und versetzen kannst. Dann kannst du die Daten auch ohne weitere Umwege rauskopieren.
Das habe ich mir auch schon überlegt, aber mir gefällt es nicht, SFML zu ändern, dann muss ich bei jedem neuen release wieder meine eigenen Änderungen reintun usw., das wollte ich wenn möglich vermeiden.
TyRoXx schrieb:
SFML ist an dieser Stelle einfach fehlerhaft (und nicht nur da). Zum Beispiel wird wahrscheinlich auch
long
nicht funktionieren, weil nurint
überladen ist.long double
undlong long
(nicht Standard, können aber die meisten Compiler) fehlen,w/char/_t *
ist unlogisch, das Verhalten fürbool
ist unklar (denn die Größe vonbool
ist Compiler-abhängig).
Außerdem kann man nicht angeben, wie die String-Länge serialisiert werden soll. Eine Beschränkung der Länge auf genau 32 Bit ist unnötig und Platzverschwendung.
In einer vernünftigen Bibliothek würde man die Operatoren für alle möglichen Typen überladen und nicht diese schwachsinnigentypedef
s verwenden. Portierbaretypedef
s für den Benutzer gibts in Boost oder<cstdint>
.Ich werd Laurent (Entwickler von SFML) mal Bescheid sagen, vll ändert er da ja mal was.
SFML werd ich aber trotzdem weiterverwenden solange ich keine vernünftige Alternative habe. Und bisher war ich mit SFML sehr zufrieden.
Edit: Eine Anfrage wegen char hab ich mal gemacht.
Int64 / long long wurde schonmal angefragt, hatte er aber nicht gemacht, weil er meinte, dass dafür htonl nicht funktioniert und es kaum jemand braucht.
-
nur zum umwandeln von daten <-> byte/char
oioioi, dann schreib dir doch einfach ne eigene kleine klasse die das macht. und besser macht als sf::Packet.
die 2 1/2 zeilen sollte dir das wert sein.
-
Ich will ja auch sowas wie endianess beachten und dann ist es nicht mehr ganz so trivial.
Dann muss man evtl. noch bytes swappen (oder htonl/htons etc. bemühen) usw..
Aber drüber nachgedacht hatte ich auch schonmal, evtl. mach ich das.Hat gerade wer code zum htonl selbst machen (bytes swappen) parat?
-
template <typename T> void swap_endianess(T* src, T* dest) { char* s = reinterpret_cast<char*>(src); char* d = reinterpret_cast<char*>(dest); for(int i = 0; i < sizeof(T); ++i) d[i] = s[length - i - 1]; }
Verwendung:
int i = 42; int j; swap_endianess(&i, &j);
-
Danke dafür.
Dann fehlen aber nochn paar Sachen.
Also erstmal muss man die eigene Endianess rausfinden.
Und wie ist das mit float/double, müssen die auch geswapped werden?
Bei SFML werden die NICHT geswapped.
-
bool little_endian() { int i = 1; return *reinterpret_cast<char*>(&i) == 1; }
Außerdem frage ich mich, wie ich nur so eine hässlichen Umwandlungs-Funktion schreiben konnte. Hier nochmal eine schönere:
template <typename T> T swap_endianess(T t) { char* data = reinterpret_cast<char*>(&t); std::reverse(data, data + sizeof(T)); return t; }
bzw hier inplace:
template <typename T> void swap_endianess(T& t) { char* data = reinterpret_cast<char*>(&t); std::reverse(data, data + sizeof(T)); }
-
Im Prinzip ist das Ganze in dieser Form ohnehin Unfug: Ein T ist im Allgemeinen nach einem swap kein T mehr.
-
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.
-
Man könnte die Bytes auch direkt in umgekehrter Reihenfolge in die Ausgabe schreiben.
-
TyRoXx schrieb:
Man könnte die Bytes auch direkt in umgekehrter Reihenfolge in die Ausgabe schreiben.
Was sich super auf die Datenrate auswirkt.
-
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.htmlT 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.