Erklärungshilfe für einen Neueinsteiger



  • Hallo Allerseits,
    wie der Titel schon sagt bin ich ein ziemlicher Neuling in Sachen programmieren. Ich versuche es mir selber beizubringen mit Hilfe vom Buch Der C++ Programmier von Ulrich Breymann und dem Internet.
    So zu meinem Problem

    const string str{"17462309"}; // aus Aufgabentext
      long int z = 0L;
      for (auto zeichen : str) {
        z *= 10;
        z += static_cast<int>(zeichen) - static_cast<int>('0');
    

    Das ist die Lösung zu einer Aufgabe, ein String Zahl umwandeln und dann die Quersumme berechnen, aber ich verstehe nicht was in den 2 Zeilen passiert.

    z *= 10;
        z += static_cast<int>(zeichen) - static_cast<int>('0');
    

    Wenn jemand Zeit hätte, mir das zu erkären, wäre ich sehr erfreut und dankbar.



  • Du willst dir mal eine ASCII-Tabelle anschauen und feststellen, in welcher Relation das Zeichen '0' (nicht die Ziffer 0) in Relation zu den anderen numerischen Zeichen steht. Dann wird dir vielleicht klar, was hier passiert.

    EDIT: long ? Wenn die Zahl nicht negativ werden kann, sollte man size_t verwenden.



  • Tja man merkt erst im Nachhinein das die Frage doof war ^^ Vielen Dank hatte das mit der ASCII Tabelle total vergessen.


  • Mod

    dachschaden schrieb:

    EDIT: long ? Wenn die Zahl nicht negativ werden kann, sollte man size_t verwenden.

    Wieso möchtest du einen Datentyp für Größenangaben zum Berechnen von Quersummen benutzen?



  • SeppJ schrieb:

    Wieso möchtest du einen Datentyp für Größenangaben zum Berechnen von Quersummen benutzen?

    Weil size_t ein Typ darstellt, welcher die Größe jedes beliebigen Objektes (auf der Maschine) speichern kann.


  • Mod

    dachschaden schrieb:

    SeppJ schrieb:

    Wieso möchtest du einen Datentyp für Größenangaben zum Berechnen von Quersummen benutzen?

    Weil size_t ein Typ darstellt, welcher die Größe jedes beliebigen Objektes (auf der Maschine) speichern kann.

    Ja? Was hat das mit Quersummen zu tun?



  • SeppJ schrieb:

    Ja? Was hat das mit Quersummen zu tun?

    Größte native Variable, die Zahlen speichern kann? *

    Oder anders: was würdest du vorschlagen?

    EDIT: *Mir geht es darum, dass man direkt sieht, dass es sich hier um eine vorzeichenlose Zahl handelt, die so groß ist wie nur möglich. Selbst, wenn man diese Größen vielleicht gar nie erreicht - size_t ist immer verfügbar, es tut nicht weh, ihn zu benutzen, und wenn er überläuft, dann hat man wenigstens etwas weniger falsch gemacht.



  • Die viel interessantere Frage ist meiner Meinung nach, wozu hier überhaupt ein static_cast<int>(...) gemacht wird. Könnte man doch auch ganz weglassen.


  • Mod

    dachschaden schrieb:

    SeppJ schrieb:

    Ja? Was hat das mit Quersummen zu tun?

    Größte native Variable, die Zahlen speichern kann?

    Das geht nicht aus der Definition hervor und selbst wenn es das täte, beantwortest du damit immer noch nicht meine Frage. Was ist beispielsweise mit uintptr_t? Das ist effektiv ein size_t, aber du würdest es sicher nicht empfehlen, oder? Weil es absolut unangemessen ist, von der Semantik her. Ebenso wie size_t selber.

    Oder anders: was würdest du vorschlagen?

    long.



  • SeppJ schrieb:

    Was ist beispielsweise mit uintptr_t? Das ist effektiv ein size_t, aber du würdest es sicher nicht empfehlen, oder?

    Nein, ist es effektiv nicht. Ausnahme sind Maschinen mit segmentierter Speicherverwaltung. Da kann ein String nur so groß wie ein Segment werden, und size_t muss diesen fassen können. uintptr_t kann aber auch für globale Adressen verwendet werden, also größer sein, als nötig ist. Das hat nichts mit der Semantik zu tun.

    SeppJ schrieb:

    long.

    Das könnte interessant auf Windows werden, welches long auch auf 64-Bit-Systemen als 32-Bit-Zahl definiert ... da muss ich nicht mal kreativ werden, um mir ein Overflow-Szenario vorzustellen. size_t dagegen ist dort auch 8 Bytes groß.

    @wob: kann eine Mikrooptimierung sein ... wenn mich mein Gedächtnis nicht trügt, sind Operationen ohne Carry-Flag marginal schneller auszuführen als mit.

    EDIT: Nein, das ist Blödsinn, wir konvertieren ja in int , nicht in unsigned ... nein, war Unsinn.


  • Mod

    dachschaden schrieb:

    technisches BlaBla.

    Merkst du was? Du willst nur Rechnen und kommst aber mit solchen Erklärungen an. Weil du mit size_t einen Datentyp gewählt hast, der eine technische Kenngröße der Maschine darstellt anstatt der Semantik "Zahl zum Rechnen".



  • Nein, ich merk es nicht, tut mir Leid. Diese technische Kenngröße ist nun mal ideal für das Berechnen solcher Zahlen.
    Und wenn man vorzeichenbehaftete Quersummen haben will, kann man immer noch ssize_t verwenden, oder eine Sprache verwenden, die einem die Bürde von Overflows abnimmt.



  • Also das ist bloss eine Übungsaufgabe aus dem ersten Kapitel. In der Übung wird nur das benutzt, was man zuvor im Kapitel gelernt hat. Natürlich kann man es besser schreiben, aber das lernt man ja später noch.



  • dachschaden schrieb:

    Nein, ich merk es nicht, tut mir Leid. Diese technische Kenngröße ist nun mal ideal für das Berechnen solcher Zahlen.
    Und wenn man vorzeichenbehaftete Quersummen haben will, kann man immer noch ssize_t verwenden, oder eine Sprache verwenden, die einem die Bürde von Overflows abnimmt.

    wenn es tatsächlich wichtig wäre, overflows auszuschließen, dann wäre - wie du schon sagst - auch size_t völlig falsch. dann wäre die aufgabe nämlich, einen typ für große zahlen zu entwickeln. size_t wäre jedenfalls auch nicht zu empfehlen. was *du* vorschlägst, müsste so aussehen:

    using big_unsigned_int = size_t;
    

    oder einfach bei int bleiben.

    im übrigen könnte ja der zu konvertierende string ein einzelnes leerzeichen sein. dann wird's auch negativ.



  • dove schrieb:

    wenn es tatsächlich wichtig wäre, overflows auszuschließen, dann wäre - wie du schon sagst - auch size_t völlig falsch.

    Lies nochmal:

    dachschaden schrieb:

    Bürde von Overflows

    Da steht nichts davon, Overflows auszuschließen, sondern nur, dass man in C/C++ mit Overflows leben und auf sie reagieren muss. Auf einen Overflow kann man mit jeden vorzeichenfreiem Typen prüfen

    if(i + x < i)
        return EOVERFLOW;
    

    Ist also schonmal eine deutliche Verbesserung gegenüber long . Egal, ob wir uns jetzt auf Windows befinden oder nicht (wegen der int32_t -Implementierung da).

    Jetzt kann man anfangen, mehr Hardware und Software auf das Problem zu werfen, auch mit dynamisch wachsenden Integern. Ist vollkommen legitim, da sag ich nichts gegen - wenn es sein muss, dann muss es sein. Worum es geht ist, dass ich in einem Fall, wie der TE ihn beschrieben hat, size_t oder ssize_t vor allen anderen Typen verwenden würde.

    Aber gut, lassen wir uns mal auf ein Gedankenexperiment ein - wir wollen einen Datentyp, der in der Lage ist, dezimale Quersummen zu berechnen. Mit jeder Stelle/Byte können wir maximal 9 auf unsere Quersumme addieren, wir können also [den maximalen Wert des Quersummentyps + 10%] Zeichen einlesen, bevor ein Overflow passiert. Für 64 Bit sind wir bei ungefähr 2.0291418e+17 (18.446.744.073.709.551.615 + 10%) ... ab dann wird's günstig, es genauso zu machen, wir du beschrieben hast. Vorausgesetzt, jeder dieser Ziffern ist eine 9 - bei kleineren Ziffern ändert sich die Anzahl der Bytes, die man einlesen kann, bevor ein Overflow passiert, entsprechend.

    Wenn man soweit gehen muss, OK. Andernfalls reicht size_t erstmal.

    dove schrieb:

    im übrigen könnte ja der zu konvertierende string ein einzelnes leerzeichen sein. dann wird's auch negativ.

    Ähh, wieso? In so einem Fall ist der eingelesene Wert 0 - weil halt nichts eingelesen wurde. Wenn man entsprechend drauf ist, packt man den Code in eine Funktion und lässt einen Fehlercode zurückgeben, der indiziert, dass der eingelesene Wert 0 ist, aber nicht, weil auch "0" drinsteht, sondern weil nichts drin ist. Also, in C jetzt. In C++ wirft man eine Exception, man lässt den Caller entscheiden, wie er damit verfährt.



  • Ich bin auch der Meinung, dass size_t für indices etc. gedacht ist.

    Wenn ich mit der Maus in VS15 über size_t fahre steht da

    typedef unsigned int size_t
    


  • dachschaden schrieb:

    ...

    ich sagte ja, wenn man es unbedingt so machen will, dann sollte man es allerdings zumindest mit einem using big_uint = size_t machen.



  • Zur size_t -Diskussion möchte ich nur kurz einwerfen, dass ich kürzlich für den Arduino Nano programmiert habe:
    Dort ist sizeof(size_t) = 2 , und dennoch könnte ich auch z.B. mit einem uint64_t rechnen. Mit letzterem kann man natürlich etwas längere Strings umwandeln 🙂

    Finnegan


Anmelden zum Antworten