Konversion zwischen arithmetischen Typen



  • Eigentlich wollte ich das schon lange mal fragen, aber hab es dann irgendwie doch nicht getan. Aufgrund eines anderen Threads hier ist die Thematik gerade wieder aktuell geworden... 🙂

    Wenn ihr zwischen mehreren arithmetischen Typen umwandelt, benutzt ihr explizite Casts? Mir scheint das zum Teil noch nützlich, da man gerade sieht, was passiert. Als Nebeneffekt bringt man allfällige Warnungen weg. Global deaktivieren möchte ich Konvertierungswarnungen eigentlich nicht, da sie mir auch bereits geholfen haben. Oder ist euch das grundsätzlich egal und euch reichen implizite Konvertierunen? Oder seid ihr da total inkonsistent? 😉

    (Und nein, es stimmt nicht, dass man Casts quasi nie benötigt. Vielleicht nicht oft, aber schon ab und zu. Ich zumindest. :))



  • Explizit, ausser eine Konstante wird zugewiesen. Fuer "float f = 1;" eine Warnung zu werfen, finde ich uebertrieben.



  • Vorab: Ich konvertiere sehr selten zwischen arithmetischen Typen.

    Aber wenn, dann unterscheide ich von Fall zu Fall: Wann "spinnt" nur der Compiler/Standard und wann mache ich tatsächlich und absichtlich einen "riskanten" cast?

    In Letzterem Fall lasse ich die Warnung stehen (wenn mir wirklich keine sinnvolle fachliche Abbildung (z.B. via numeric_limits) einfällt) - ist mir als stete Erinnerung lieber.

    Aber wie gesagt: Habe ich eher selten.

    Gruß,

    Simon2.



  • knivil schrieb:

    Fuer "float f = 1;" eine Warnung zu werfen, finde ich uebertrieben.

    Ja, klar. Wobei ich glaube, dass (zumindest unter MSVC++) für Konstanten auch keine Warnungen entstehen.

    Simon2 schrieb:

    In Letzterem Fall lasse ich die Warnung stehen (wenn mir wirklich keine sinnvolle fachliche Abbildung (z.B. via numeric_limits) einfällt) - ist mir als stete Erinnerung lieber.

    Das wäre bei mir eben eher so ein Fall, wo ein static_cast durch die Länge des Schlüsselwortes und Syntaxhighlighting gut sichtbar im Code bleibt (C- und Funktionsstil-Casts benutze ich eigentlich nie, unter anderem aus dem Grund, dass sie nicht so leicht erkennbar sind). Aber die ständigen Warnungen beim Kompiliervorgang mag ich nicht, eben weil sie schnell untergehen oder zu weniger Aufmerksamkeit verleiten.

    Simon2 schrieb:

    wenn mir wirklich keine sinnvolle fachliche Abbildung (z.B. via numeric_limits) einfällt

    Hm, hier verstehe ich nicht ganz, was du meinst. Könntest du das vielleicht ein wenig erläutern?



  • Hi Nexus,

    zu dem Thema "übersehen von Warnings" habe ich schon im auslösenden Thread geantwortet.

    Nexus schrieb:

    ...

    Simon2 schrieb:

    wenn mir wirklich keine sinnvolle fachliche Abbildung (z.B. via numeric_limits) einfällt

    Hm, hier verstehe ich nicht ganz, was du meinst. Könntest du das vielleicht ein wenig erläutern?

    naja, vor dem cast versichere ich mich halt (z.B. via numeric_limits::max()), dass der Wert tatsächlich in den Zieltypen passt - evtl. in einer eigenen Funktion ("float2int()" oder sowas).
    Aber stimmt natürlich, letztlich caste ich natürlich doch.
    Ein cast sagt ja auch nur "Ich weiß es besser als Du Compiler" - und ich will dann auch sicherstellen, dass ich es tatsächlich besser weiß. 😉

    Gruß,

    Simon2.



  • Okay, danke für die Antwort.

    Ich bin mir ehrlich gesagt oft nicht ganz sicher, ob ich besser casten soll oder nicht. Zum einen denke ich, dann ist es eindeutig, und man sieht, dass eine Typumwandlung stattfindet, zum anderen finde ich ständiges Casten etwas fragwürdig, wenn man schon implizite Konversionen hat. Von daher bin ich nicht immer ganz konsequent...

    Hm, gibt es noch mehr Leute, die dazu etwas sagen möchten? 🙂



  • Wenn unbedingt sein muss, dann verwende ich auch explizite casts.

    Aber mir ist es auch schon passiert, dass ich nach einem Weilchen irgendwo einen cast hatte und ich darauf hin alles hintern umgeschrieben habe, damit der cast nicht nötig ist.



  • Für arithmetische Umwandlungen verwende ich i.d.R. immer Casts. Allerdings nicht static_cast<> - das wäre viel zu häßlich -, sondern den Cast im Konstruktor-Stil, also

    int round (float f)
    { return int (f + 0.5f); }
    

  • Administrator

    1. Ich habe eigentlich kaum solche Casts, da ich meistens entsprechende typedefs brauche oder ähnliches. Also überall der gleiche Typ verändert wird.
    2. Falls es einen hat und ich genau weiss, was hier gemacht werden soll, dann kommt ein static_cast zum Einsatz.
    3. Falls es Bereichsprüfung und ähnliches braucht, dann hilft dir Boost:
    http://www.boost.org/doc/libs/1_39_0/libs/numeric/conversion/doc/html/index.html

    Grüssli



  • Vielen Dank für die Antworten!

    Ich habe bei mir eben schon ab und zu Casts, da ich Koordinaten von Spielobjekten teilweise als float s speichere und teilweise als int (das muss so sein, weil gewisse Objekte nur ganzzahlige Koordinaten haben können). Allerdings könnte ich versuchen, durch entsprechende Funktionen die Anzahl Casts zu minimieren, was ich wahrscheinlich demnächst tun werde.


  • Administrator

    Nexus schrieb:

    ... und teilweise als int (das muss so sein, weil gewisse Objekte nur ganzzahlige Koordinaten haben können).

    Wieso speicherst du es intern nicht als float und sorgst im Getter oder Setter dafür, dass es nur Ganzzahlen sind? Zum Beispiel über ceil oder floor . Wenn du mit SFML arbeitest, was ich irgendwie stark vermute, brauchst du am Ende doch sowieso einen float für die Position oder Grösse.
    Allenfalls könntest du auch einen RealInteger oder sowas bauen, damit es noch ein wenig klarer ist für den Leser oder Benutzer der Bibliothek.

    Grüssli



  • Es geht um Lifte, die sich zwischen zwei Positionen bewegen. Da müssen die Koordinaten exakt sein, da ich auf Gleichheit prüfen möchte (wenn das Ende erreicht ist, soll der Lift wieder umkehren). Anfangs hatte ich int , jetzt bin ich auf boost::rational<int> umgestiegen, um flexibler zu sein.

    An der Schnittstelle habe ich dennoch eine Funktion GetPosition() , die die einen float -Vektor zurückgibt (aktuelle Position). Zudem habe ich noch eine Methode, die die Startposition des Liftes zurückgibt ( GetOriginalPosition() ). Die gibt einen int -Vektor zurück, weil die Startposition immer ganzzahlig ist (genauer gesagt, jeweils ein Vielfaches der Tilegrösse, da Lifte gerade an Tile-Ecken starten).

    Ja, ich arbeite mit SFML. Doch manchmal ist es da selber nicht ganz konsistent. Will ich zum Beispiel mit sf::Shape::Rectangle() ein Rechteck erstellen, muss ich float -Koordinaten übergeben. Wenn die Koordinaten von der Bildschirmgrösse abhängen, greife ich auf sf::Window::GetWidth() zu, welches int zurückgibt. Also wäre streng genommen wieder ein Cast erforderlich...


  • Administrator

    Nexus schrieb:

    Es geht um Lifte, die sich zwischen zwei Positionen bewegen.

    Da würde ich eher einen int nehmen für das Stockwerk und dann einen float für Stockwerkhöhen und entsprechend berechnen lassen, wodurch man einen float bekommt für die Position.
    Ka ob das gehen würde, kommt natürlich darauf an, wie deine Lifte aussehen, aber fände ich ein typisches Beispiel für nicht genügend differenzierte Informationen/Daten 😉

    Nexus schrieb:

    Wenn die Koordinaten von der Bildschirmgrösse abhängen, greife ich auf sf::Window::GetWidth() zu, welches int zurückgibt. Also wäre streng genommen wieder ein Cast erforderlich...

    Kommt darauf an, ob du dann mit einer float Variable rechnest, dann passiert der cast explizit. Allerdings ist mir das noch nicht aufgefallen, wäre aber mal interessant im SFML Forum nachzufragen, ob hier nicht eher ein float angebracht wäre, vor allem wegen der Konsistenz. Wäre sicher eine interessante Diskussion 🙂

    Grüssli



  • Dravere schrieb:

    Da würde ich eher einen int nehmen für das Stockwerk und dann einen float für Stockwerkhöhen und entsprechend berechnen lassen, wodurch man einen float bekommt für die Position.
    Ka ob das gehen würde, kommt natürlich darauf an, wie deine Lifte aussehen, aber fände ich ein typisches Beispiel für nicht genügend differenzierte Informationen/Daten 😉

    Nicht solche klassischen Aufzüge, sondern Jump'n'Run-Lifte. 🙂
    Also bewegliche Plattformen, die einen Anfangs- und Endpunkt haben, wie du sie vielleicht von Super Mario kennst. Und da ist ein Bruch wohl keine schlechte Wahl (er wird ja nur intern verwendet), um die Position exakt zu halten, aber trotzdem nicht nur Ganzzahlen zu erlauben.

    Dravere schrieb:

    Allerdings ist mir das noch nicht aufgefallen, wäre aber mal interessant im SFML Forum nachzufragen, ob hier nicht eher ein float angebracht wäre, vor allem wegen der Konsistenz. Wäre sicher eine interessante Diskussion 🙂

    Hm, es hat eben schon seinen Grund, warum sf::Window Ganzzahlen zurückgibt, schliesslich kann die Fenstergrösse nur eine ganzzahlige Anzahl von Pixeln sein.

    Bei den Zeichenobjekten (von sf::Drawable abgeleitete Klassen, darunter sf::Shape ) hingegen wurden float s gewählt, um flexibler bezüglich der Position zu sein. Weil viele Spielobjekte sich auch um reelle Zahlen fortbewegen können. Andererseits ist das wieder nur relevant, wenn man seine Spiellogik nicht von der Grafik getrennt hält und direkt sf::Sprite s als Klasse für seine Spielfiguren nimmt. Hmm... 😉


  • Administrator

    Nexus schrieb:

    Nicht solche klassischen Aufzüge, sondern Jump'n'Run-Lifte. 🙂
    Also bewegliche Plattformen, die einen Anfangs- und Endpunkt haben, wie du sie vielleicht von Super Mario kennst. Und da ist ein Bruch wohl keine schlechte Wahl (er wird ja nur intern verwendet), um die Position exakt zu halten, aber trotzdem nicht nur Ganzzahlen zu erlauben.

    Dann gäbe es die Möglichkeit 0 (unten) und 1 (oben). Oder man führt Grenzbereiche ein, in welchen man ein- oder aussteigen kann.

    Nexus schrieb:

    Hm, es hat eben schon seinen Grund, warum sf::Window Ganzzahlen zurückgibt, schliesslich kann die Fenstergrösse nur eine ganzzahlige Anzahl von Pixeln sein.

    Und "Zeichenobjekte" (was für ein Name? 😮 :D) haben keine feste Pixelposition schlussendlich?
    Wofür braucht man die Fenstergrösse in SFML, ausser für die Berechnung der Grösse oder Position von Objekten? Mir will da nichts sinnvolles einfallen 😉

    Grüssli



  • Dravere schrieb:

    Dann gäbe es die Möglichkeit 0 (unten) und 1 (oben). Oder man führt Grenzbereiche ein, in welchen man ein- oder aussteigen kann.

    Ich weiss jetzt nicht genau, was du meinst, aber irgendwie habe ich das Gefühl, wir verstehen unter Lift nicht das Gleiche. Bei mir sind die Lifte bewegliche Plattformen, die sich in 8 Richtungen fortbewegen können. Diese haben Wegpunkte gespeichert, eine Bahn muss also nicht geradlinig sein, sondern kann sich aus mehreren geradlinigen Stücken zusammensetzen. Doch speichern musst du die aktuelle Position so oder so. Und da reichen 2 Möglichkeiten nicht. Statt eines ungenauen float s für die Koordinaten habe ich eben boost::rational genommen.

    Dravere schrieb:

    Und "Zeichenobjekte" (was für ein Name? 😮 :D) haben keine feste Pixelposition schlussendlich?

    Doch. Aber "schlussendlich" ist bereit derart Low-Level, dass man sich selber nicht darum kümmern muss. OpenGL nimmt selber float s, wieso sollte ich also zuerst runden? Koordinaten haben ausserdem nicht immer Pixel als Masseinheit, denke zum Beispiel an verschiedene Viewports. Deshalb ist es auch sinnvoll, dass SFML float -Koordinaten nimmt. Zumal man wohl in den meisten Fällen Fliesskommazahlen für spiellogische Koordinaten verwendet.

    Dravere schrieb:

    Wofür braucht man die Fenstergrösse in SFML, ausser für die Berechnung der Grösse oder Position von Objekten? Mir will da nichts sinnvolles einfallen 😉

    Naja, mir fällt jetzt auch nicht gerade ein Fall ein. Aber ich finde unsigned int trotzdem sinnvoll, eben weil nur Ganzzahlen angenommen werden können. Ein float für eine Fenstergrösse wäre verwirrend und inkonsistent, man müsste dann entsprechend die Fenstergrösse auch auf zwei float s setzen können. Im Gegensatz zu den Zeichenobjekten (hast du den Begriff wirklich noch nie gehört? Ich finde gerade keinen besseren...) macht das hier absolut keinen Sinn.


  • Administrator

    Nexus schrieb:

    ... Lifte mit Wegpunkten ...

    Ich würde zwar immer noch sagen, dass es anders ginge, denn ich hatte durchaus auch sowas im Kopf. Aber ist ja auch nicht so weiter wichtig, vielleicht sehe ich dich noch irgendwann im MSN, dann können wir das noch genauer diskutieren, sofern ich endlich mal wieder online gehen würde ^^"

    Nexus schrieb:

    OpenGL nimmt selber float s, wieso sollte ich also zuerst runden? Koordinaten haben ausserdem nicht immer Pixel als Masseinheit, denke zum Beispiel an verschiedene Viewports. Deshalb ist es auch sinnvoll, dass SFML float -Koordinaten nimmt. Zumal man wohl in den meisten Fällen Fliesskommazahlen für spiellogische Koordinaten verwendet.

    Ich war ja auch nicht gegen float Werte. Ich bin nur der Meinung, dass man die verschiedenen Argumente für float Werte bei Figuren auch fast 1:1 auf das Fenster anwenden kann 😉

    Nexus schrieb:

    Ein float für eine Fenstergrösse wäre verwirrend und inkonsistent, man müsste dann entsprechend die Fenstergrösse auch auf zwei float s setzen können. Im Gegensatz zu den Zeichenobjekten [...] macht das hier absolut keinen Sinn.

    Ich fände es aber noch gut, wenn man auch die Fenstergrösse und Position als float Werte setzen könnte. Zum Beispiel könntest du das Fenster selbst animieren, dann hast du auch float Werte, welche du setzen musst. Wieso vorher runden, wieso kann dies nicht das Framework für dich übernehmen? Das ist doch völlig Low-Level 😉

    Nexus schrieb:

    ... (hast du den Begriff wirklich noch nie gehört? Ich finde gerade keinen besseren...) ...

    Ich würde es eher eine Figur nennen. Oder ein graphisches Objekt. Ein Zeichenobjekt klingt einfach nur seltsam. Wenn schon eher noch Zeichnungsobjekt, aber auch das ist ... naja

    Grüssli



  • Dravere schrieb:

    Ich fände es aber noch gut, wenn man auch die Fenstergrösse und Position als float Werte setzen könnte. Zum Beispiel könntest du das Fenster selbst animieren, dann hast du auch float Werte, welche du setzen musst. Wieso vorher runden, wieso kann dies nicht das Framework für dich übernehmen? Das ist doch völlig Low-Level 😉

    Naja. Wie oft animiert man sein Fenster, und wie oft seine Spielfiguren? 😉
    Bei Spielfiguren ist es teilweise wirklich notwendig, die Position mit float -Koordinaten zu setzen. Zum Beispiel, wenn man heranzoomt. Beim Fenster wäre es mehr Faulheit, float s zu nehmen, um sich das Runden zu ersparen. Denn für das Fenster selbst sind nur ganze Pixel relevant, und zwar immer. Es gibt wahrscheinlich auch Fälle, wo man auf die Anzahl Pixel angewiesen ist, und da ist man wieder froh über genaue Angaben.

    Auch das mit dem Low-Level kannst du nicht 1:1 übertragen. Bei SFML müsstest du, um direkt die Pixelkoordinaten von Spielfiguren setzen zu können, Zugriff auf den Viewport und die Matrizen von OpenGL haben. Ich finde es gut, dass dieser Teil gekapselt wird. Beim Fenster hingegen ist es wirklich nur ein Runden, was in einer Zeile gemacht werden kann.

    Dravere schrieb:

    Ich würde es eher eine Figur nennen. Oder ein graphisches Objekt. Ein Zeichenobjekt klingt einfach nur seltsam. Wenn schon eher noch Zeichnungsobjekt, aber auch das ist ... naja

    Hmm, stimmt schon, ich habe mir gar nicht soviel dabei überlegt. Figur triffts wohl am besten... 🙂

    Vielen Dank übrigens für die Antworten, Dravere! Ja, eventuell können wir uns da noch einmal ausführlicher drüber unterhalten... 😉



  • Nexus schrieb:

    Es geht um Lifte, die sich zwischen zwei Positionen bewegen. Da müssen die Koordinaten exakt sein, da ich auf Gleichheit prüfen möchte (wenn das Ende erreicht ist, soll der Lift wieder umkehren). Anfangs hatte ich int , jetzt bin ich auf boost::rational<int> umgestiegen, um flexibler zu sein.

    An der Schnittstelle habe ich dennoch eine Funktion GetPosition() , die die einen float -Vektor zurückgibt (aktuelle Position). Zudem habe ich noch eine Methode, die die Startposition des Liftes zurückgibt ( GetOriginalPosition() ). Die gibt einen int -Vektor zurück, weil die Startposition immer ganzzahlig ist (genauer gesagt, jeweils ein Vielfaches der Tilegrösse, da Lifte gerade an Tile-Ecken starten).

    Ja, ich arbeite mit SFML. Doch manchmal ist es da selber nicht ganz konsistent. Will ich zum Beispiel mit sf::Shape::Rectangle() ein Rechteck erstellen, muss ich float -Koordinaten übergeben. Wenn die Koordinaten von der Bildschirmgrösse abhängen, greife ich auf sf::Window::GetWidth() zu, welches int zurückgibt. Also wäre streng genommen wieder ein Cast erforderlich...


Anmelden zum Antworten