Fragen zu 128-Bit Integer



  • Hallo COM,

    System: Linux x64-86

    ich probiere mich gerade an einigen Datentypen, u.a. dem GCC bekannten
    "__int128_t" und "__uint128_t".

    Übersetzen lassen sich diese und auch das Rechnen funktioniert wunderbar.
    Ich habe aber gerade ein Problem mit der Ausgabe via printf(,) und std::cout.

    1.) printf(,):
    Ich weiß von anderen Datentypen wie "__int64_t", dass es zumindest für printf(,) spezielle PRI-Makros für solche Datentypen gibt:
    http://openbook.galileocomputing.de/c_von_a_bis_z/030_c_anhang_b_007.htm#mj5d49f76cb13e7b31342925f336de6e63

    Folgende Aufrufe funktionieren:

    printf("x: %"PRIi64"\n",Variable)";
    printf("x: %"PRIu64"\n",Variable)";
    

    Doch für die __int128_t-Datentypen irgendwie nicht.
    Folgendes funktioniert nicht (Compiler-Fehler):

    printf("x: %"PRIi128"\n",Variable)";
    printf("x: %"PRIu128"\n",Variable)";
    

    Compiler-Aufruf:

    g++ -std=c++0x -m64 -fopenmp -Wall -Wextra -pedantic -pedantic-errors -O3 -s sizeofs_main.cpp -o sizeofs_main
    

    Compiler-Output:

    sizeofs_main.cpp:84: error: expected ‘)’ before ‘PRIu128’
    sizeofs_main.cpp:84: warning: spurious trailing ‘%’ in format
    sizeofs_main.cpp:84: warning: too many arguments for format
    

    Da es die beiden Datentypen:

    __int128_t
    __uint128_t
    

    aber gibt, frage ich mich nun, wie das Makro hierfür heißen muss?

    2.) std::cout:
    Ebenso würde ich gerne wissen, wie ich das mit std:cout ausgeben kann.
    Mit:

    __int128_t Var1 = 1024;
    cout << Var1 << endl;
    

    funktionierts zumindest nicht. Compiler-Output:

    sizeofs_main.cpp:84: error: ambiguous overload for ‘operator<<’ in ‘std::cout << Var31’
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:165: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:169: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:173: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/bits/ostream.tcc:91: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:180: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/bits/ostream.tcc:105: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:191: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:200: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:204: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:209: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:213: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:221: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:451: note:                 std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, char) [with _CharT = char, _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:457: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, char) [with _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:463: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, signed char) [with _Traits = std::char_traits<char>]
    /usr/lib/gcc/x86_64-redhat-linux/4.4.5/../../../../include/c++/4.4.5/ostream:468: note:                 std::basic_ostream<char, _Traits>& std::operator<<(std::basic_ostream<char, _Traits>&, unsigned char) [with _Traits = std::char_traits<char>]
    

    Bis einschließlich __uint64_t hingegen schon:

    __uint64_t Var2 = 1024;
    cout << Var2 << endl;
    

    THX schonmal im Voraus!

    Grüße

    Schlitzauge 🙂 🙂 🙂 🙂



  • Zunächst:

    Schlitzauge schrieb:

    Ich weiß von anderen Datentypen wie "__int64_t", dass es zumindest für printf(,) spezielle PRI-Makros für solche Datentypen gibt:
    http://openbook.galileocomputing.de/c_von_a_bis_z/030_c_anhang_b_007.htm#mj5d49f76cb13e7b31342925f336de6e63

    Such dir eine bessere Quelle. Der Autor des Buches, das du da benutzt, kennt weder C noch C++ richtig.

    Ansonsten: __int128_t ist eine in keinem Standard festgeschriebene gcc-Spezialität, die meines Wissens bislang auch kein anderer Compiler beherrscht. Der Grund dafür, dass sie kein anderer Compiler beherrscht, ist, dass bislang keine CPU dafür Opcodes hat; gcc beherrscht ihn vermutlich, weil mal jemand einen entsprechenden Patch eingeschickt hat und niemand einen Grund sah, diesen abzulehnen. Allerdings führt __int128_t auch hier ein Schattendasein - weder ist __int128_t auf allen Plattformen, die der gcc unterstützt, vorhanden, noch wird viel Arbeit in seine Integration gesteckt. Unter anderem gibt es in den Bibliotheken, die üblicherweise mit dem gcc kommen, keine Ausgabefunktionen für ihn.



  • Wahrscheinlich weil bei der Ausgabe eines 128 Bit Ints niemand was mit einer 42-telligen Zahl anfangen kann. Es ist schwierig sie mit einer anderen Ausgabe am Bildschirm zu vergleichen oder gar einzugeben. Man verrutscht leicht in der Stelle. Demgegenueber ist eine einfache Ausgabe und Eingabe als Hexwert trivial und kann selbst implementiert werden.



  • Gibt es also keine Ausgabemöglichkeit für __[u]int128_t?
    Mag sein, dass er schlecht implementiert sei, aber ich kann mir nicht vorstellen, dass ihn jemand implementiert, ohne ihn mal ausgegeben zu haben.
    Es muss doch eine Möglichkeit mit printf(), std:cout oder meinetwegen auch mit einer anderen Methode, geben???

    Das es kein Standard ist, weiß ich selbst. Es muss auch für ein Experiment auch nur gerade auf meinem System laufen. Deklarieren und Rechnen mit diesen beiden 128-Bit-Typen funktioniert, ebenso das Kompilieren.
    Bleibt nur noch die Frage nach der Ausgabe?

    Wahrscheinlich weil bei der Ausgabe eines 128 Bit Ints niemand was mit einer 42-telligen Zahl anfangen kann.

    Naja. Streng genommen kann cout und printf() auch den Datentyp "long double", selbst bis 2^512. Von daher...

    Grüße

    Schlitzauge 🙂 🙂

    PS:
    Wer sagt denn, dass ich das Buche habe oder ich dieses als einzige Quelle missbrauche? In dem Fall, stimmt das aber mit den PRI-Makros für printf().
    Andere Recherche-Eregbnisse brachten mich zum __int128_t. Hat nichts mit den Buch zu tun.



  • Naja, so eine Funktion ist ja schnell zusammengestrickt. Beispiel:

    #include <iostream>
    
    std::ostream &operator<<(std::ostream &out, __uint128_t x) {
      if(x >= 10) out << x / 10;
      return out << static_cast<unsigned>(x % 10);
    }
    
    std::ostream &operator<<(std::ostream &out, __int128_t x) {
      if(x < 0) {
        out << '-';
        x = -x;
      }
    
      return out << static_cast<__uint128_t>( x);
    }
    
    int main() {
      __int128_t test = -1234567;
    
      std::cout << test << std::endl;
    }
    


  • @seldon: Hab großen Dank. Kannte ich so noch gar nicht. Ist aber im Nachhinein leicht verständlich.

    Habs soweit jetzt hinbekommen. Hier ein Bsp.-Prog. für std::cout:
    INTS128.cpp:

    #include <climits>
    #include <cstdint>
    #include <cinttypes>
    #include <cfloat>
    #include <cmath>
    #include <cstdlib>
    #include <cstdio>
    #include <stdio.h>
    #include <iostream>
    
    using namespace std;
    
    std::ostream &operator<<(std::ostream &out, __uint128_t x)
    {
      if(x >= 10)
      {
        out << x / 10;
      }
      return out << static_cast<unsigned>(x % 10);
    }
    
    std::ostream &operator<<(std::ostream &out, __int128_t x)
    {
      if(x < 0)
      {
        out << '-';
        x = -x;
      }
      return out << static_cast<__uint128_t>( x);
    }
    
    int main(int argc, char *argv[])
    {
      __int128_t         Var31 = 0, tmp31 = 0;
      __uint128_t        Var32 = 0, tmp32 = 1;
    
      cout << "128-Bit Integer\n-----------------\n";
    
      __int128_t INT128_MIN = (-170141183460469231731.687303715884105728) * pow(10,18);
      __int128_t INT128_MAX = ( 170141183460469231731.687303715884105727) * pow(10,18);
    
      //cout << "Vermutet:\nINT128-MIN:" << INT128_MIN << "\nINT128-MAX: " << INT128_MAX << "\n\nBerechnet:\n";
    
      __int128_t TMP128 = 0;
      TMP128 = INT128_MAX + 1;                       // ergibt INT128-MIN
      cout << "INT128-MIN: " << TMP128 << "\n";      // Ausgabe von INT128-MIN
      TMP128 = INT128_MIN - 1;                       // ergibt INT128-MAX
      cout << "INT128-MAX:  " << TMP128 << "\n";     // Ausgabe von INT128-MAX
    
      __uint128_t UINT128_MAX = (340282366920938463463.374607431768211455) * pow(10,18);
      __uint128_t UINT128_MIN = 0/* * pow(10,18)*/;
    
      __uint128_t TMPu128 = 0;
      TMPu128 = UINT128_MAX + 1;                     // ergibt UINT128-MIN
      cout << "UINT128-MIN: " << TMPu128 << "\n";    // Ausgabe von UINT128-MIN
      TMPu128 = UINT128_MIN - 1;                     // ergibt UINT128-MAX
      cout << "UINT128-MAX: " << TMPu128 << "\n";    // Ausgabe von UINT128-MAX
    
      getchar();
      return 0;
    }
    

    OS: Linux x64-86 (bei mir Scientific Linux 6.1 x64 (up2date))

    g++(GCC)-Version:
    g++ (GCC) 4.4.5 20110214 (Red Hat 4.4.5-6)

    Glibc: x86_x64 - v2.12-1.25.el6_1.3

    Compile (release):
    g++ -std=c++0x -m64 -fopenmp -Wall -Wextra -pedantic -pedantic-errors -O3 -s source.cpp -o dest

    Output (exec):

    128-Bit Integer
    -----------------
    INT128-MIN: -170141183460469231731687303715884105728
    INT128-MAX:  170141183460469231731687303715884105727
    UINT128-MIN: 0
    UINT128-MAX: 340282366920938463463374607431768211455
    

    -----------------------
    @seldo, wüsstest Du noch oder jemand anderes, wie man auch printf(,) dies beibringen kann?

    Und kann man und wenn ja wie, printf(,) weitere Makros beibringen?

    Ich wüsste da zwar jetzt ne Möglichkeit einfach einen Output mittels std:cout in eine String- bzw. char[]-Variable zu stecken und diese fprint(,) zu übergeben, allerdings würde ich nur ungern printf(,) mit std::cout kreuzen wollen. Lieber wäre mir, wenn ich wahlweise mein überladenes std::cout oder printf(,) verwenden könnte, ohne dass das eine vom anderen abhängig ist.

    THX im Voraus,

    Grüße

    Schlitzauge 🙂



  • Die Lösung ist, printf einfach nicht zu verwenden. Wenn du unbedingt eine printf-artige Funktion willst, dann bastel dir einen Wrapper um std::cout. Da du GCC verwendest, ist das mit Variadic Templates sehr einfach.



  • eine moeglichkeit waere:

    const char* prn_int(int x)
    {
       static const int size = 20;
       static char buf[size];
       char *p = buf + size - 1;
       *p = '\0';
       --p;
       bool sign = false;
    
       if(x == 0)
       {
          *p = '0';
          return p;
       }
    
       if(x < 0)
       {
          sign = true;
          x *= -1;
       }
    
       while(x > 0)
       {
          if(x < 10)
          {
             *p = '0' + static_cast<char>(x);
             x = 0;
          }
          else
          {
             *p = '0' + static_cast<char>(x % 10);
             x /= 10;
          }
    
          --p;
       }
    
       if(sign == true)
          *p = '-';
       else
          ++p;
    
       return p;
    }
    
    int main()
    {
       printf("test %s", prn_int(0));
    }
    

    ich hab hier in dem beispiel anstatt deinem int128 nen normalen int genommen. musst natuerlich dann anpassen.

    Meep Meep


  • Mod

    Meep Meep schrieb:

    eine moeglichkeit waere:

    Die ist dann allerdings nicht reentrant,

    printf("test %s %s", prn_int(0), prn_int(1));
    

    geht so schon mal nicht.



  • na dann macht man buffer halt thread local.

    sollte ja nur als beispiel dienen.

    Meep Meep



  • Wieso nicht einfach stringstreams mit der oben genannten Funktion benutzen und so Sachen wie c_str() nutzen.



  • Die Lösung ist, printf einfach nicht zu verwenden. Wenn du unbedingt eine printf-artige Funktion willst, dann bastel dir einen Wrapper um std::cout. Da du GCC verwendest, ist das mit Variadic Templates sehr einfach.

    Wie würde das dann aussehen. Mit Templates hatte ich bisher noch nicht so viel zu tun.

    na dann macht man buffer halt thread local.

    Wie meinst Du das? Wie müsste dann Deine Funktion aussehen, dass sie Thread locale ist? Was muss da genau verändert werden?

    Wieso nicht einfach stringstreams mit der oben genannten Funktion benutzen und so Sachen wie c_str() nutzen.

    Natürlich. An sowas hab ich auch schon längst gedacht. Wie ich schon erwähnte, kann ich auch meine überladenen std::OStream<<-Operatoren nutzen und eine print-Funktion für die 128-Bit-INT-Typen schreiben, welche dann einfach als Parameter printf(,) übergeben wird/werden.

    Eine Ausgabe-Funktion zu schreiben, stellt kein Problem dar. Ich suche aus reiner Neugier eine Möglichkeit, die [U]INT128-Typen bzw. Variablen davon, direkt in printf(,) zu nutzen, so wie ich es jetzt schon mit std::cout kann.

    Für Typen wie "__int64_t" gibt es für printf(,) bereits Lösungen, in Form von [PRI-]Makros, oder wie auch immer man sowas nennt, Bsp.:

    __int64_t Variable = 1024;
    printf("x: %"PRIi64"\n",Variable)";
    

    Es wäre toll, wenn es auch PRId128, PRIi128 oder PRIu128 geben würde.
    In der Doku zu meinem Compiler oder den Bibliotheken oder im I-net kann ich leider dazu nichts finden. Zumindest sehe ich es nicht, wenn es denn etwas Derartiges gibt. Wenn jemand was finden sollte, bitte posten. Vlt. heißen die PRI-Makro´s für die 128-Bit INT-Typen einfach nur anders.

    Oder kann man eigene PRI-Makro´s schreiben und diese dann einfach in printf(,) verwenden? Oder könnte man printf(,) auch einfach überladen?

    Der Grund, weshalb ich nicht einfach auf reine C++-Lösungen, wie die der std::[O]Streams oder Stringstreams ausweiche, ist der, dass ich hin und wieder leider nur reines C verwenden muss bzw. möchte. Lösungen mit C++-Elementen hab ich schon (teils Eigenrecherchen und Experimente, teils tatkräftiger Hilfen Eurerseits [HABT GROßEN DANK!]). Insb. was Threadsicherheit angeht, was ich insb. beim Einsatz von OpenMP benötige, würde ich lieber auf printf(,), anstatt auf std:cout setzen. Ich krieg zwar mit beiden Methoden ne Ausgabe hin, bei std::cout ist aber mehr Arbeit von Nöten und zieht alles nur unnötig in die Länge, auch wenns, wie ich finde, deutlich komfortabler ist, aber das ist ja bekanntlich Geschmackssache. Ebenso möchte ich nicht immer C-Style mit C++-Style mixen wollen.

    Idialerweise peile ich folgendes Ziel an (wenn es denn möglich wäre^^):

    __int128_t Variable128 = 1024;
    printf("x: %"PRIi128"\n",Variable128);
    // oder meinetwegen auch mit anderen "Platzhaltern"
    printf("x: %"IRGENDWAS"\n",Variable128);
    

    Ziel sollte es sein, in printf(,) die Variablen einfach direkt zu übergeben, nicht über Funktionen. Wenn natürlich nichts anderes geht, hab ich auch kein Problem damit, auf Funktionen zu setzen oder gleich mit C++-Methoden (std::Ostream, Stringstream, etc.) zu arbeiten. Es ist ja jetzt auch kein absolutes MustHave, sondern reine Neugier, wie man printf(,) zum Kooperieren bringen könnte.

    Abgesehen vom Hauptthema: 128-Bit-Integer. Seit C++ kann man Operatoren super leicht überladen, siehe Bsp. std:Ostream<< (oben). Nun kann man mit struct und class, auch eigene Datentypen schreiben, z.B. BRÜCHE. Mit dem Überladen von std::Ostream<< (std::cout) kann ich so einfach auch eigene Datentypen mit std::cout verwenden. Wie aber hat man das damals bzw. noch Heute in C gemacht?
    U.a. ist die C-Standard-Ausgabe-Funktion bekanntlich printf(,) für sowas. Darum meine Neugier und Nachfrage.

    Ich suche jetzt schon seit Tagen, finde aber nichts Richtiges.

    Grüße

    Schlitzauge 🙂



  • void myprintf(char const* format)
    {
        std::cout << format;
    }
    
    template <typename Head, typename... Tail>
    void myprintf(char const* format, Head&& head, Tail&&... tail)
    {
        while(*str != '%')
            std::cout << *str++;
    
        std::cout << head;
    
        printf(++str, std::forward<Tail>(tail)...);
    }
    

    Und wenns noch threadsafe sein soll, dann bastel dir noch ne Wrapper-Funktion mit Mutex drumherum. Außerdem bezweifle ich mal, dass printf threadsafe ist.



  • Ich habe jetzt folgendes:

    INTS128_2.cpp

    #include <climits>
    #include <cstdint>
    #include <cinttypes>
    #include <cfloat>
    #include <cmath>
    #include <string>  //std:string
    #include <string.h>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <stdio.h>
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <termios.h>
    
    using namespace std;
    
    // Möglichkeit 1 (für std::cout)
    std::ostream &operator<<(std::ostream &out, __uint128_t x)
    {
      if(x >= 10)
      {
        out << x / 10;
      }
      return out << static_cast<unsigned>(x % 10);
    }
    
    std::ostream &operator<<(std::ostream &out, __int128_t x)
    {
      if(x < 0)
      {
        out << '-';
        x = -x;
      }
      return out << static_cast<__uint128_t>( x);
    }
    
    // Möglichkeit 2 (für printf() mit C++-Elementen)
    const char* INT128ToCSTR(__int128_t x)
    {
      stringstream sstr;
      sstr<<x;
      return sstr.str().c_str();
    }
    
    const char* UINT128ToCSTR(__uint128_t x)
    {
      stringstream sstr;
      sstr<<x;
      return sstr.str().c_str();
    }
    
    // Möglichkeit 3 (für printf() mit C-Elementen)
    const char* prn_int128(__int128_t x)
    {
      static const __int128_t size = 20;
      static char buf[size];
      char *p = buf + size - 1;
      *p = '\0';
      --p;
      bool sign = false;
    
      if(x == 0)
      {
        *p = '0';
        return p;
      }
      if(x < 0)
      {
        sign = true;
        x *= -1;
      }
    
      while(x > 0)
      {
        if(x < 10)
        {
          *p = '0' + static_cast<char>(x);
          x = 0;
        }
        else
        {
          *p = '0' + static_cast<char>(x % 10);
          x /= 10;
        }
        --p;
      }
    
      if(sign == true)
      {
        *p = '-';
      }
      else
      {
        ++p;
      }
      return p;
    }
    
    int main(int argc, char *argv[])
    {
      __int128_t         Var31 = 0, tmp31 = 0;
      __uint128_t        Var32 = 0, tmp32 = 1;
    
      cout << "128-Bit Integer\n=====================================================\n";
      cout << "\n+Mit std::cout:\n----------------------------------------------------\n";
    
      __int128_t INT128_MIN = (-170141183460469231731.687303715884105728) * pow(10,18);
      __int128_t INT128_MAX = ( 170141183460469231731.687303715884105727) * pow(10,18);
    
      //cout << "Vermutet:\nINT128-MIN:" << INT128_MIN << "\nINT128-MAX: " << INT128_MAX << "\n\nBerechnet:\n";
    
      __int128_t TMP128 = 0;
      TMP128 = INT128_MAX + 1;                       // ergibt INT128-MIN
      cout << "INT128-MIN: " << TMP128 << "\n";      // Ausgabe von INT128-MIN
      TMP128 = INT128_MIN - 1;                       // ergibt INT128-MAX
      cout << "INT128-MAX:  " << TMP128 << "\n";     // Ausgabe von INT128-MAX
    
      __uint128_t UINT128_MAX = (340282366920938463463.374607431768211455) * pow(10,18);
      __uint128_t UINT128_MIN = 0/* * pow(10,18)*/;
    
      __uint128_t TMPu128 = 0;
      TMPu128 = UINT128_MAX + 1;                     // ergibt UINT128-MIN
      cout << "UINT128-MIN: " << TMPu128 << "\n";    // Ausgabe von UINT128-MIN
      TMPu128 = UINT128_MIN - 1;                     // ergibt UINT128-MAX
      cout << "UINT128-MAX: " << TMPu128 << "\n";    // Ausgabe von UINT128-MAX
    
      cout << "\n+Mit printf(,) UND prn_int128():\n----------------------------------------------------\n";
      printf("x: %s\n",prn_int128(1024));                          //geht
      printf("x: %s, y: %s\n",prn_int128(2048),prn_int128(4096));  //geht nicht
    
      cout << "\n+Mit printf(,) UND [U]INT128ToCSTR(): (EINZELN)\n----------------------------------------------------\n";
      printf("INT128-MIN: %s\n",INT128ToCSTR(INT128_MIN));      //geht
      printf("INT128-MAX:  %s\n",INT128ToCSTR(INT128_MAX));     //geht
      printf("UINT128-MIN: %s\n",UINT128ToCSTR(UINT128_MIN));   //geht
      printf("UINT128-MAX: %s\n",UINT128ToCSTR(UINT128_MAX));   //geht
    
      cout << "\n+Mit printf(,) UND [U]INT128ToCSTR(): (ZUSAMMEN)\n----------------------------------------------------\n";
      //geht nicht
      printf("INT128-MIN:%s\nINT128-MAX:%s\nUINT128-MIN:%s\nUINT128-MAX:%s\n",INT128ToCSTR(INT128_MIN),INT128ToCSTR(INT128_MAX),UINT128ToCSTR(UINT128_MIN),UINT128ToCSTR(UINT128_MAX));
    
      getchar();
      return 0;
    }
    

    Output (Exec):

    128-Bit Integer
    =====================================================
    
    +Mit std::cout:
    ----------------------------------------------------
    INT128-MIN: -170141183460469231731687303715884105728
    INT128-MAX:  170141183460469231731687303715884105727
    UINT128-MIN: 0
    UINT128-MAX: 340282366920938463463374607431768211455
    
    +Mit printf(,) UND prn_int128():
    ----------------------------------------------------
    x: 1024
    x: 2048, y: 2048
    
    +Mit printf(,) UND [U]INT128ToCSTR(): (EINZELN)
    ----------------------------------------------------
    INT128-MIN: -170141183460469231731687303715884105728
    INT128-MAX:  170141183460469231731687303715884105727
    UINT128-MIN: 0
    UINT128-MAX: 340282366920938463463374607431768211455
    
    +Mit printf(,) UND [U]INT128ToCSTR(): (ZUSAMMEN)
    ----------------------------------------------------
    INT128-MIN:-170141183460469231731687303715884105728
    INT128-MAX:-170141183460469231731687303715884105728
    UINT128-MIN:0
    UINT128-MAX:-170141183460469231731687303715884105728
    

    ------------------------------
    Wie schon Letztens erwähnt, funktioniert das Arbeiten mit std::cout Ostream<< und damit auch mit stringstream´s.
    Dennoch hab ich noch eine Frage / ein Problem mit folgenden printf()-Alternativen:

    Camper schrieb:

    Meep Meep schrieb:
    eine moeglichkeit waere:

    Die ist dann allerdings nicht reentrant,

    printf("test %s %s", prn_int(0), prn_int(1));
    

    geht so schon mal nicht.
    Meep Meep antwortete:

    na dann macht man buffer halt thread local.
    sollte ja nur als beispiel dienen.

    Das Bezieht sich auf die prn_int128(__int128_t)-Funktion.
    Wie beim Output zu sehen ("+Mit printf(,) UND prn_int128():"), stimmt das natürlich.

    Gleiches bzw. ähnliches Problem scheint auch bei meinen zwei neuen Funktionen INT128ToCSTR() und UINT128ToCSTR() vorhanden zu sein, wie der Output ("+Mit printf(,) UND [U]INT128ToCSTR(): (ZUSAMMEN))" zeigt. Also zumindest in Kombination mit printf().

    Was heißt eigentlich eine Variable "thread local" zu machen? Im Moment arbeite ich ohne irgendwelche Parallelisierungstechniken a´la OpenMP. Also reine Single-Thread/-Prozess-Programmierung. Gleichwohl benötige ich später natürlich Threadsicherheit, aber das mal jetzt außen vor.

    Wie müssten denn die Funktionen prn_int128(__int128_t), INT128ToCSTR(), sowie UINT128ToCSTR() aussehen, damit die Ausgaben wieder stimmen, wenn man diese Funktionen bei printf(,) mehrfach als Parameter übergeben möchte?



  • Einfach das static weg? Wie kommt man überhaupt auf die blöde Idee, da ein static hinzumachen? Das habe ich mich schon so oft bei so manchen C-Programmierern gefragt.



  • // Möglichkeit 2 (für printf() mit C++-Elementen)
    const char* INT128ToCSTR(__int128_t x)
    {
      stringstream sstr;
      sstr<<x;
      return sstr.str().c_str();
    }
    
    const char* UINT128ToCSTR(__uint128_t x)
    {
      stringstream sstr;
      sstr<<x;
      return sstr.str().c_str();
    }
    

    Falsch, undefiniertes Verhalten, der stringstream gibt den Speicher für den String im Destruktor frei.



  • 314159265358979 schrieb:

    Einfach das static weg? Wie kommt man überhaupt auf die blöde Idee, da ein static hinzumachen? Das habe ich mich schon so oft bei so manchen C-Programmierern gefragt.

    Hm, klingt logisch. OK, bringt aber keinen Erfolg?:

    const char* prn_int128(__int128_t x)
    {
      const __int128_t size = 20;
      char buf[size];
      char *p = buf + size - 1;
      *p = '\0';
      --p;
      bool sign = false;
    
      if(x == 0)
      {
        *p = '0';
        return p;
      }
      if(x < 0)
      {
        sign = true;
        x *= -1;
      }
    
      while(x > 0)
      {
        if(x < 10)
        {
          *p = '0' + static_cast<char>(x);
          x = 0;
        }
        else
        {
          *p = '0' + static_cast<char>(x % 10);
          x /= 10;
        }
        --p;
      }
    
      if(sign == true)
      {
        *p = '-';
      }
      else
      {
        ++p;
      }
      return p;
    }
    

    Ethon schrieb:

    Falsch, undefiniertes Verhalten, der stringstream gibt den Speicher für den String im Destruktor frei.

    ??? Das versteh jetzt einer. Wenn ich die Funktionen mit printf(,) einzeln aufrufe (siehe Output: ""\n+Mit printf(,) UND [U]INT128ToCSTR(): (EINZELN)\n"), funktionierts doch. Was genau hast Du gemeint?



  • Schlitzauge schrieb:

    Hm, klingt logisch. OK, bringt aber keinen Erfolg?:

    Du darfst natürlich keinen Zeiger auf eine lokale Variable zurückgeben. Nimm einen out-Parameter. War ein denkfehler meinerseits. Sorry.

    Ethon schrieb:

    ??? Das versteh jetzt einer. Wenn ich die Funktionen mit printf(,) einzeln aufrufe (siehe Output: ""\n+Mit printf(,) UND [U]INT128ToCSTR(): (EINZELN)\n"), funktionierts doch. Was genau hast Du gemeint?

    Der stringstream hat sich Speicher angefordert. Wenn der Scope verlassen wird, wird der Speicher freigegeben. Auch hier musst du einen out-Parameter nehmen. (Oder C-Strings komplett lassen.)

    P.S.: Warum schreibst du eigentlich immer "printf(,)", also wozu da der ','?



  • Schlitzauge schrieb:

    Ethon schrieb:

    Falsch, undefiniertes Verhalten, der stringstream gibt den Speicher für den String im Destruktor frei.

    ??? Das versteh jetzt einer. Wenn [...] funktionierts doch. Was genau hast Du gemeint?

    Undefiniertes Verhalten bedeutet, dass es funktionieren kann, aber nicht muss. Wenn du Pech hast, passiert an einem anderen Ort im Programm was ganz Merkwürdiges -> dein Code ist verbuggt.

    Mach das undefinierte Verhalten weg.



  • ??? Das versteh jetzt einer. Wenn ich die Funktionen mit printf(,) einzeln aufrufe (siehe Output: ""\n+Mit printf(,) UND [U]INT128ToCSTR(): (EINZELN)\n"), funktionierts doch. Was genau hast Du gemeint?

    So wäre es zb korrekt:

    // Möglichkeit 2 (für printf() mit C++-Elementen)
    string INT128ToSTR(__int128_t x)
    {
      stringstream sstr;
      sstr<<x;
      return sstr.str();
    }
    string UINT128ToSTR(__uint128_t x)
    {
      stringstream sstr;
      sstr<<x;
      return sstr.str();
    } 
    
    ................
    
    printf("%s", INT128ToSTR(123456789).c_str());
    


  • Ethon schrieb:

    So wäre es zb korrekt:

    JA ok, aber dabei ist der Rückgabetyp "string". Ich wollte gerne aber ohne string auskommen, sondern auf Standard-C-String (char[]) setzen, welcher anschließend von den zwei Funktionen jeweils zurückgegeben wird.
    Ich wollte das Konvertieren von stringstream nach c_str() gerne inline in der Funktion ausführen lassen, sodass ich auch wirklich nur C-Strings (char[]) zurückgebe und ich einfach nur die Funktionen in printf() verwenden kann, ohne sonstiges wie ".c_str()".


Anmelden zum Antworten