Funktion abhängig von der Datenbreite des Typs?
-
Nexus schrieb:
Dreieckstausch mit
memcpy()?Beispiel, bitte?
Nexus schrieb:
Dass das Verhalten von byteweisen Operationen nur für PODs definiert ist, brauch ich wohl nicht zu sagen...
Nein, ist klar.
-
Nick Unbekannt schrieb:
Wie würdet ihr eine Byteswapping-Funktion implementieren? Falls es da eine Standardfunktion für gibt, bitte auch nennen. Ich hab die paar Zeilen nur lieber schnell selbst geschrieben, weil ich nichts passendes in kürzerer Zeit gefunden habe. Meine Frage bezog sich nur darauf, ob es eleganter geht. Meine Frage hat sich also somit geklärt. Auch weil noch ein paar Details dazu gekommen sind, die andere Anforderungen überflüssig gemacht haben. Außer jemand hat generell noch einen Vorschlag, wie man eine Byteswap-Funktion realisieren sollte. Bitte nicht die htonX()-Funktionen nennen, die swappen nämlich nur, wenn es notwendig ist.
Ich gehe mal davon aus, dass du die bytes im Objekt selber swappen willst.
Damit da nichts undefiniertes bei rumkommt, darf es sich bei den betroffenen Objekten nur um PODs handeln. Damit wird das byte-swappen "nur noch" implementation defined. Wozu auch immer du das brauchen solltest, portabel ist das in keiner Weise, zumal noch so Dinge wie Padding und Alignment ne Rolle spielen dürften. Die Frage ist also: wozu brauchst du das?
Schreiben würd ichs in etwa so:template <size_t N> void swapBytesN(void* ptr) { char* raw_bytes = reinterpret_cast<char*>(ptr); for (size_t i = 0; i < N/2; ++i) { std::swap(raw_bytes[i], raw_bytes[N-i]); } } template <typename POD_t> void swapBytes(POD_t& pod) { swapBytesN<sizeof(POD_t)>(&pod); }
-
pumuckl schrieb:
Ich gehe mal davon aus, dass du die bytes im Objekt selber swappen willst.
Ja.
pumuckl schrieb:
Damit da nichts undefiniertes bei rumkommt, darf es sich bei den betroffenen Objekten nur um PODs handeln.
Die Grunddatentypen reichen vollkommen aus.
pumuckl schrieb:
zumal noch so Dinge wie Padding und Alignment ne Rolle spielen dürften.
Gibt es nicht, nur Grunddatentypen.
Deine Lösung dürfte wohl das sein, was Nexus vorgeschlagen hat. Ich werde es mir mal genauer betrachten.
-
Auch bei den Grunddatentypen ist die Byte-Darstellung implementation-defined. Portabel ist das nicht.
Ausserdem würde dich jeder C-Programmierer noch fester hauen als SeppJ und ich zusammen, wenn er sähe, wie kompliziert du einen Byte-Tausch umsetzt

-
Nexus schrieb:
Auch bei den Grunddatentypen ist die Byte-Darstellung implementation-defined. Portabel ist das nicht.
Meinst du jetzt die Endianness oder etwas ganz anderes? Die Endianness soll je gerade mit dieser Aktion abgefangen werden. Die Datentypgrößen passen auch, die werden extra so gewählt. Dass sich verschiedene Fließkomma-Darstellungen so beißen werden ist klar, dass müsste man dann gesondert behandeln. Und zum Beispiel vorher das Format anpassen. Sonst würde mir da jetzt kein weiterer Fallstrick einfallen?
Nexus schrieb:
Ausserdem würde dich jeder C-Programmierer noch fester hauen als SeppJ und ich zusammen, wenn er sähe, wie kompliziert du einen Byte-Tausch umsetzt

Wieso kompliziert? Ich hab die übliche Bitshifterei gemacht, so wie man sie auch zu tausenden im Netz findet. Welche Variante nun die bessere ist, müsste man schauen. An meiner ist aber gar nichts kompliziert, ganz im Gegenteil, die ist sogar extrem einfach gehalten.

-
Nick Unbekannt schrieb:
Meinst du jetzt die Endianness oder etwas ganz anderes? Die Endianness soll je gerade mit dieser Aktion abgefangen werden.
Klingt furchtbar nach Hack.
PS:
es würde ungemein helfen wenn du endlich sagst WAS du machen willst.
-
Wüsste nicht warum? Und fühle mich in meiner Ansicht bestärkt, da es ein gewöhnlicher Weg ist.
-
Nachdem dich schon vier Leute gefragt haben, wäre es vielleicht schon einmal an der Zeit, etwas über deine eigentlichen Absichten preiszugeben.
-
Nick Unbekannt schrieb:
Wüsste nicht warum? Und fühle mich in meiner Ansicht bestärkt, da es ein gewöhnlicher Weg ist.
Eben nicht. network-to-host/host-to-network byteorder basiert auf Typen Ebene und nicht auf Byte ebene. Aber wenn du eh alles weisst, warum fragst du hier dann?
Ich bin mir ziemlich sicher dass man dein Problem anders viel viel besser lösen kann.
-
Das ganze soll Daten zwischen verschiedenen Plattformen austauschen. Deswegen kein Padding (Alignment) und keine Endianness. Das Padding zu eliminieren ist kein Problem, es wird einfach keins erlaubt. Die Endianness ist da schon schwieriger, da keine einheitliche Form möglich ist. Deswegen müssen die Daten in eine bekannte Reihenfolge gebracht werden, ähnlich der ntohX()-Funktionen. Warum diese nicht gehen? Weil diese auch swappen würden, wenn es unnötig wäre.
Wenn ihr das schon so ins Detail wissen wollt, wäre ich hingegen interessiert, was ich übersehen haben könnte?* gleiche Bitbreite
* gleiche Endianness
* gleiche Padding/Alignment
* gleiches. Float Format
* bool ? (wobei Boolean allgemein keine Rolle spielt?)
* nur PODEben nicht. network-to-host/host-to-network byteorder basiert auf Typen Ebene und nicht auf Byte ebene.
Den Satz versteh ich nicht?
Ich hab mir hier mal eine Beispiel-Implementierung angesehen und die machen exakt das selbe, was ich mache.
http://www.jbox.dk/sanos/source/include/netinet/in.h.htmlWenn ich also einen Denkfehler habe, dann werte ihn nicht als ignorantes Gehabe, sondern korrigiere mich bitte!
-
Die machen es auf Typ Ebene. Man sagt: das ist ein int, swappe die Bytes.
Du sagst: das ist ein 3 Byte Datentyp - swappe die Bytes. Was aber wenn es zB ein float ist? Oder zB eine struct aus 3 chars?
Deshalb betrachtet man den Typen, nicht die Anzahl der Bytes.
Aber OK, was genau willst du denn anders machen als die Standard Funktionen und warum genau brauchst du die größe des Typen als Template Argument? Du hast immer noch nichts verraten.
-
Shade Of Mine schrieb:
Die machen es auf Typ Ebene. Man sagt: das ist ein int, swappe die Bytes.
Du sagst: das ist ein 3 Byte Datentyp - swappe die Bytes. Was aber wenn es zB ein float ist? Oder zB eine struct aus 3 chars?
Zusammengesetzte Daten, werden nicht geswappt, weil die Reihenfolge der Member ja bestehen soll. Nur Grunddatentypen, dass wird auch weiter vorne abgefangen.
Shade Of Mine schrieb:
Aber OK, was genau willst du denn anders machen als die Standard Funktionen und warum genau brauchst du die größe des Typen als Template Argument? Du hast immer noch nichts verraten.
Weil mir der Compiler automatisch die richtige Funktion raus suchen soll. Hätte ich jetzt nur eine Spezialisierung für int, dann würde diese nicht mehr bei long greifen, obwohl beide hier 32Bit sind. Deswegen die Selektion über sizeof. Außerdem muss ich so nicht wissen, dass long == int ist, um einen expliziten Aufruf zu machen.
-
void MySwap32(unsigned int& d) { unsigned int c = 0; c |= ((d ) & 0xFF) << 24; c |= ((d>> 8) & 0xFF) << 16; c |= ((d>>16) & 0xFF) << 8; c |= ((d>>24) & 0xFF); d = c; } template<typename T> void MySwap(T& t) { size_t size = sizeof(T); size/=4; unsigned int* addr = reinterpret_cast<unsigned int*>(&t); for(size_t i=0; i<size; ++i) { MySwap32(*addr++); } }
-
Nick Unbekannt schrieb:
Weil mir der Compiler automatisch die richtige Funktion raus suchen soll. Hätte ich jetzt nur eine Spezialisierung für int, dann würde diese nicht mehr bei long greifen, obwohl beide hier 32Bit sind. Deswegen die Selektion über sizeof. Außerdem muss ich so nicht wissen, dass long == int ist, um einen expliziten Aufruf zu machen.
Dafür ist überladung da

Denn sizeof(int) muss nicht gleich sizeof(long) sein. Genauso wie sizeof(float) zB gleich sizeof(int) sein kann...Und was genau ist an den Standard Funktionen schlecht?
-
Shade Of Mine schrieb:
Dafür ist überladung da

Müsste ich mir mal genauer anschauen, ob es da wirklich keine Lücken gibt. Wie zum Beispiel typedefs.
Shade Of Mine schrieb:
Und was genau ist an den Standard Funktionen schlecht?
Ich will nur swappen, wenn beide Teilnehmer eine unterschiedliche Endianness haben. Die Standardfunktionen verbergen aber vor dir die Endianess. Also entweder sie swappen oder sind ein nop. Und auf einem Big-Endian-System würde der swap-Befehl in ein nop laufen.
-
Nick Unbekannt schrieb:
Ich will nur swappen, wenn beide Teilnehmer eine unterschiedliche Endianness haben. Die Standardfunktionen verbergen aber vor dir die Endianess. Also entweder sie swappen oder sind ein nop. Und auf einem Big-Endian-System würde der swap-Befehl in ein nop laufen.
dh die Daten sind einmal big endian und einmal little endian? Je nachdem ob beide Teilnehmer das selbe verwenden oder nicht? mhm... finde ich ungut - das swappen kostet quasi nichts und es beugt eine Menge Fehler vor.
Aber selbst wenn du das unbedingt so willst, so ist normale Funktionsüberladung immer noch die einfachste Lösung. Vorallem aber die Robusteste.
-
Nick Unbekannt schrieb:
Shade Of Mine schrieb:
Dafür ist überladung da

Müsste ich mir mal genauer anschauen, ob es da wirklich keine Lücken gibt. Wie zum Beispiel typedefs.
typedeferstellt nur einen anderen Namen für denselben Typen, definiert aber keinen eigenen Typ.Wenn du wirklich nur auf so wenig Typen arbeiten möchtest, ist die Überladung definitiv der bessere Weg. Bei den Templates ist immer die Gefahr da, dass einmal durch Unachtsamkeit ein anderer Typ übergeben wird. Zum Beispiel weil irgendwo ein
typedefgeändert wird, von einemintzu einemstructirgendwas. Damit dies beim Template abgefangen wird, müsste man Templatemetaprogrammierungstricks einsetzen. Bei der Überladung ist das bereits durch den Kompiler abgesichert.Grüssli