StringLoader
-
Oh ja, an Alignment habe ich in der Tat keinen Gedanken verschwendet, da hast hast Du natürlich absolut recht! Aber memcpy sieht immer so teuer aus.
Dann eben so:
std::wstring MyLoadString(UINT uID) { union { WCHAR wsz[sizeof(WCHAR*) / sizeof(WCHAR)]; WCHAR* pwsz; }; int len = LoadStringW(GetModuleHandle(nullptr), uID, wsz, 0); return std::wstring(pwsz, len); }
-
Immer noch nicht standardkonform fürchte ich.
Nimmmemcpy
.
Der Compiler optimiert das vermutlich eh komplett weg.
-
hustbaer schrieb:
Immer noch nicht standardkonform fürchte ich.
Weil? Alignment kann es ja nun nicht mehr sein.
-
Naja, ist vielleicht ne Grauzone.
Vorweg: ich mein(t)e mit "nicht standardkonform" natürlich dass das Programm laut Standard "undefined behavior" (UB) hat.
Du übergibst nen
WCHAR*
aufwsz
undLoadStringW
schreibt da was rein.
Dann liest du auspwsz
was raus.
Würdest du direkt was nachwsz
schreiben wäre es deswegen UB, weil du ne Union nur als das lesen darfst als was sie zuletzt beschrieben wurde.Wäre
LoadStringW
in deinem Programm implementiert, und würde direkt den übergebenen Zeiger dereferenzieren um reinzuschreiben (also ohnememcpy
oder "selbst mittelschar
-Zeiger kopieren"), dann wäre es zusätzlich nochmal UB wegen einer strict aliasing Verletzung*.Jetzt ist
LoadStringW
natürlich extern implementiert, und man könnte argumentieren dass der Compiler daher ja nicht wissen kann wieLoadStringW
den Wert schreibt, und es daher OK sein muss. Allerdings übergibst du anLoadStringW
nen Zeiger aufwsz
, und nicht einen aufpwsz
. Daher könnte man genau so argumentieren dassLoadStringW
auch nurwsz
beschreiben kann.
Leider reichen meine Kenntnisse des Standard nicht aus um mich hier weiter festzulegen. Ich vermute dass klar aus dem Standard hervorgeht ob es OK ist oder nicht. Aber selbst wenn es OK sein sollte, würde ich den Code lieber mitmemcpy
schreiben. Einfach weil es mitmemcpy
sicher OK ist, und ich keinen guten Grund sehe es ohnememcpy
zu schreiben.* Die genaue strict-aliasing Regel bitte selbst nachzulesen. Hab nicht alle Details exakt im Kopf, und diese Regel ist mir auch etwas zu heikel als dass ich versuchen würde sie mal eben schnell vereinfacht zusammenzufassen.
-
hustbaer schrieb:
Würdest du direkt was nach
wsz
schreiben wäre es deswegen UB, weil du ne Union nur als das lesen darfst als was sie zuletzt beschrieben wurde.Naja, dann eben doch den Cast, das ist doch ganz egal. Die Union stellt doch trotzdem sicher, dass die Ausrichtung passt.
Ansonsten wird mir das hier deutlich zu esoterisch. Wenn das UB ist, dann bitte sehr. Das nehme ich gerne und bewusst in Kauf (noch). Ich arbeite hier viel zu viel mit ganz kleinen Systemen, als das ich mir das nutzlose Kopieren von Daten leisten kann und will. Und wegen irgendwelcher Phantome, die sich zu zudem nicht einmal richtig beim Namen nennen lassen und sich vielleicht am 03.03.33 auswirken, werde ich in dieser Richtung sicherlich nichts ändern.
Das ist natürlich nur meine Meinung, kann selbstverständlich auch völliger Scheiß sein. Aber solange ich nicht weiß was genau das Problem ist und nicht eine einzige Implementierung kenne, die darüber tatsächlich stolpert...
-
@Mox
Strict aliasing Verletzungen sind mit Compilern wie GCC oder Clang IIRC gar kein "esoterisches" Problem das sich nicht auswirkt, sondern durchaus real.Was das "unnötige Kopieren" angeht: probier doch einfach mal aus was dein Compiler für ein fixed-size 4 oder 8 Byte memcpy (mit Optimierungen) für Code generiert. Normalerweise sollte davon nichts mehr übrig bleiben. (Ausser Source oder Target sind nicht lokale Variablen, dann wird ein Load oder Store oder evtl. sogar ein Load UND ein Store übrig bleiben - das selbe was mit ner Union oder reinterpret_cast auch gebraucht wird.)
-
Gut, wir haben also ein reales Problem. Darf ich fragen, was genau das Problem ist?
Davon ab: Ich habe solche und solche Compiler im Einsatz. Nicht alle optimieren gleich gut. Von daher wollte ich nicht so viel Energie darauf verschwenden, praktisch nicht existierende Probleme zu lösen.
-
-
Frage: "•Is there any way to work around this problem?"
Antwort: "You could use a union to represent the memory you need to reinterpret"
-
Kommentar zur akzeptierten Antwort:
Just a warning, that it's unspecified behaviour to use an union by writing to one member and reading from another, according to the C++ standard. So it may work, it may not.
Bitte auch beachten dass C++ hier andere Regeln als C hat.
Bei C ist der Umweg über ne union offiziell OK. Mit C++ ist er offiziell (=laut Standard) nicht OK. Wobei viele (alle?) C++ Compiler es trotzdem unterstützen.
-
Also mMm. beste Option ist
memcpy
.
Wenn dumemcpy
unbedingt vermeiden willst nimm neunion
.
Auf jeden Fall nichtreinterpret_cast
.
-
hustbaer schrieb:
Also mMm. beste Option ist
memcpy
.
Wenn dumemcpy
unbedingt vermeiden willst nimm neunion
.
Auf jeden Fall nichtreinterpret_cast
.Ich muss zwingend casten. Du hast mir doch weiter oben erklärt, dass ich das Feld pwsz nicht benutzen darf, da ich es nicht beschrieben habe. Also ist das einfach nur noch so da, wegen der Ausrichtung.
Weißt du eigentlich noch, welches Problem Du mir einreden möchtest?
-
Ich will dir gar kein Problem "einreden".
Ich versuche dir klarzumachen was der C++ Standard über den Code sagt den du schreibst.
Welche Variante aus welchem Grund UB ist hab ich auch schon beschrieben.Wenns dich nicht interessiert, dann lass deinen Code so wie er ist.
Wenn schon, dann google die Stichworte die hier gefallen sind einfach selbst.ps: Was ich mit meinem letzten Beitrag gemeint hatte: der
union
-Trick ist "weniger falsch" als derreinterpret_cast
. Oder eben anders gesagt: derreinterpret_cast
ist so ziemlich die schlimmste denkbare Variante.
-
hustbaer schrieb:
Wenn schon, dann google die Stichworte die hier gefallen sind einfach selbst.
Das werde ich ganz sicher nicht tun. Wenn Du hier UB siehst, wirst Du schon Ross und Reiter direkt beim Namen nennen müssen. Ansonsten gehe ich weiter davon aus, dass Du das nicht existierende Problem selber nicht so ganz verstehst. Mit "IIRC" und "vielleicht 'ne Grauzone" und einem Link, der mich bestätigt, überzeugst Du mich jedenfalls nicht.
Aber lassen wir das. Ich mache sowieso was ich meine machen zu müssen.
-
Ja, mach was du willst. Interessiert mich nicht wirklich. Wenn du mir nix glauben willst, dann lass es halt.
Ich hoffe ich muss nie Code von dir warten.
-
hustbaer schrieb:
Ich hoffe ich muss nie Code von dir warten.
Na klar, der musste noch kommen. Selber keine Ahnung, aber immer feste drauf. Vollidiot.
-
-
Freund Mox, der der keine Ahnung hat, bist du.
Aber klar. Weil ich mir bei einem sehr spezifischen Punkt nicht sicher bin, und es auch noch gewagt habe darauf hinzuweisen, hab ich keine Ahnung. Du spinnst ja.
ps: Und der Link bestätigt dich nicht. Du träumst halt nur und ignorierst alles was dir nicht in den Kram passt, wie z.B.
hustbaer schrieb:
Kommentar zur akzeptierten Antwort:
Just a warning, that it's unspecified behaviour to use an union by writing to one member and reading from another, according to the C++ standard. So it may work, it may not.
Bitte auch beachten dass C++ hier andere Regeln als C hat.
Bei C ist der Umweg über ne union offiziell OK. Mit C++ ist er offiziell (=laut Standard) nicht OK. Wobei viele (alle?) C++ Compiler es trotzdem unterstützen.Und jetzt geh weiter träumen.
-
Wenn selbst reinterpret_cast so unsicher ist, dass es nur dazu taugt, in einen anderen Typ und wieder zurück zum ursprünglichen Typ zu casten, wofür ist das dann in der Praxis noch gut?
-
reinterpret_cast
ist zu wenig zu gebrauchen. Ist jetzt aber auch keine grosse Überraschung. Bzw. sollte keine sein.Das Problem ist dabei aber gar nicht der
reinterpret_cast
selbst, sondern:- Dass ein
WCHAR*
nen anderes (strikteres) alignment requirement haben könnte als einWCHAR[2]
- Dass das Objekt ein
WCHAR[2]
ist, man es aber alsWCHAR*
liest. Was eben nicht erlaubt ist.
reinterpret_cast
hat damit nur insofern zu tun als dass er in diesem Beispiel verwendet wird um den Zeiger zu konvertieren, der dann verwendet wird um den "bösen" Zugriff zu machen.
- Dass ein