String-Cast zu long long statt long

  • C++

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.

    String-Cast zu long long statt long

    Hallo,

    ich habe bei Youtube Javidx9 s Video "What are Pointers" angesehen und habe hier und da mal etwas nachgebaut, rein zu Übungszwecken.
    Ich schrieb mir gerade mit MS Word eine schöne Zusammenfassung über Pointer. Ich stellte die Adressen und die Werte in den Adressen dar. Nun fiel mir eine Sache auf:

    Warum muss ich bei einem 64-Bit-System zu long long statt long casten? Bei Nichteinhaltung kommt die Warnung "Zeigerverkürzung" C4311. Ich weiß, dass ich, im Gegensatz zu Pointern auf Zahlen, eben casten muss, wenn ich die Adresse des Wertes haben will, weil Zeigername sonst als String interpretiert wird.

    C-Quellcode

    1. int main(void)
    2. {
    3. char SomeString[] = "HELLO";
    4. char* pSomeString = SomeString;
    5. cout << (long long)pSomeString << " = " << pSomeString << ", erster Buchstabe = " << *(pSomeString) << endl;
    6. //int für 32-Bit-Systeme "Wert" HELLO "Wert" an der 1. Stelle (H)
    7. //long long für 64-Bit-Systeme
    8. return 0;
    9. }


    Danke!
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Um das zu verstehen musst du erst einmal Wissen wie das RAM System funktioniert.
    Es gibt nämlich eine maximale Anzahl an Speicheraddressen die du belegen kannst.

    Auf einer 32 bit Maschine wäre der höchste Wert einer Adresse 4,294,967,296 in dezimaler Darstellung.
    Das sind ungefähr so viel wie 4GB RAM, mehr kann einfach nicht addressiert werden. (es gibt da zwar Tricks und Workarounds, darum geht es aber nicht)
    Du wirst aber niemals 4 Gb zu Gesicht bekommen da allein das Betriebssystem und die Hardware schon einiges für sich selbst beanspruchen.

    Für ein 64 bit System, aber, gilt diese Grenze nicht. Da wird "etwas" höher angesetzt und zwar endet der Wert für 64 bit bei 18,446,744,073,709,551,615, was natürlich deutlich höher ist.
    Es entspricht Ungefähr 16 Exabyte an RAM.
    daher muss auch der Datentyp mindestens 64 bit addressieren können.

    Nun bleibt nur noch die Frage wieso es long long und nicht long ist, richtig?
    Das liegt daran, dass ein normaler long Datentyp nicht garantiert immer 64 bit haben wird.
    In manchen Implementation (sei es aufgrund des Betriebssystems, des Compilers ect.) hat er nämlich nur 32 bit. Diese sind dafür aber für diesen Datentyp garantiert.
    Windows scheint das mal so und mal so zu definieren, meiner Meinung nach ist es da ein wenig undurchsichtig, allerdings sollte man nicht mit dem Schicksal verhandeln, gehe lieber auf Nummer sicher.

    Genauso ist es für long long garantiert 64 bit zu haben, egal in welcher Implementation.
    Und da auf einem 64 bit System die Adressen bis zu 64 bit groß sein können, muss der Datentyp auch mindestens 64 bit groß sein.

    Mit long long bist du also immer auf der Sicheren Seite. :)
    Besser noch unsigned long long, denn hat long long nur 64 bit und du gehst über eine gewissen Wert drüber hinaus, wird dein integer overflowen und fängt im negativen Bereich wieder an!

    Edit:
    Du befindest dich in C++ und nicht C, daher empfehle ich dir C++ Style casting zu verwenden.
    Es ist halt einfacher Probleme damit ausfindig zu machen. In diesem Fall also reinterpret_cast<unsigned long long>(pSomeString).
    C casting erlaubt dir alles, ist daher umso gefährlicher! ;)
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Elanda“ ()

    Danke @Elanda für die ausführliche und gute Antwort!

    Das liegt daran, dass ein normaler long Datentyp nicht garantiert immer 64 bit haben wird. In manchen Implementation (sei es aufgrund des Betriebssystems, des Compilers ect.) hat er nämlich nur 32 bit. ​
    Das wusste ich nicht. Ich habe mir zwar gedacht, dass es einen Sicherheitsgedanken hat, aber dies hätte ich nicht erwartet.
    ​Windows scheint das mal so und mal so zu definieren
    ||

    Und danke hierfür!

    C-Quellcode

    1. ​reinterpret_cast<unsigned long long>(pSomeString)
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Noch einen kleinen Hinweis zum Ende, weil ich denke das ich dir da jetzt einen ein wenig gefährlichen Tipp gegeben habe.

    Für diesen Zweck musst du zwar reinterpret_cast einsetzen, sei aber auch damit vorsichtig, dieser sollte auch nur dann eingesetzt werden wenn wirklich kein anderer Type-cast operator funktioniert und du dir sicher bist das du weißt was du da tust.

    Normalerweise würdest du entweder static_cast für normale Typenkonversionen verwenden, oder dynamic_cast für polymorphe Konversionen.
    Dann gibt es da noch const_cast, aber über den würde ich gar nicht erst nachdenken.
    ----------------------------------------------------------------------------------------------------------------------

    Hier könnte meine Signatur stehen, aber die ist mir abfußen gekommen.

    ----------------------------------------------------------------------------------------------------------------------
    Elanda Ok gut!
    Darf ich dich noch fragen, warum man hier (ausnahmsweise) reinterpret_cast benutzen muss? Oder andersrum, warum es hier am ehesten geeignet ist?
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Du castest einen Zeigertypen zu einer Zahl. Das ist grundsätzlich erstmal inkompatibel. Ein Zeiger ist halt keine Zahl. Deswegen der reinterpret_cast. Der Compiler castet nicht, sondern interpretiert die Daten einfach anders. Wenn man da nicht weiß was man macht, endet das schlecht. Also nach Möglichkeit vermeiden. Ausserdem caste nicht nach long long, sondern nach std::intptr_t bzw std::uintptr_t. Diese habe nämlich immer die Größe eines Zeigers der aktuellen Plattform und Architektur. Würde ich trotzdem nicht empfehlen.

    std::cout gibt dir aber auch die Adresse eines Zeigers aus (außer char* natürlich) du kannst also auch zu einem Zeigertypen casten. Also caste am Besten zu void* für die Ausgabe der Speicheradresse. Hier nimmst du dann einen [bb]static_cast<void*>(string)[/bb] ;)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Gonger96“ ()