Fragen zu 128-Bit Integer
-
Schlitzauge schrieb:
Ich verwende zwar bei jedem der drei Funktionsaufrufe das gleiche char-Array,
Das.
hustbaer schrieb:
@camper:
Die Ellipse nicht, aber dafür sollte doch das grauenhaftei128
Makro sorgen.
Da steht dann im Endeffekt japrintf("test: %s -> %s\n", (const char*)myint(12), (const char*)myint(24));
Abgesehen davon dass ich es grässlich finde... funktionieren müsste das IMO schon.
Ok, hätte nicht bloß quer lesen sollen... da der Bezeichner klein geschrieben wird, habe ich nicht an ein Makro gedacht.
-
Was wie was DAS?
Verstehe nicht so recht.Meine Vermutung liegt zwar auch bei der Verwendung von nur einem char-Array, aber ehrlich gesagt möchte ich nicht für jeden printf()-Wert ein extra Array anlegen müssen. Ich verstehe nicht, warum es mit einem Array nicht funktionieren sollte.
Wie genau geht printf() bei der Interpretation denn vor?Hätte denn wer nen Lösungsvorschlag, wie ich es auch mit einem char-Array lösen könnte? Ich bin langsam mit meinem Latein am Ende.
Wie gesagt, ausschließlich bzgl. dieser C-Funktion. Lösungen und Implementierungen mit C++-Elementen habe ich schon zu Genüge (herzlichen THX nochmal!).
Grüße
Schlitzauge
-
Meine Vermutung liegt zwar auch bei der Verwendung von nur einem char-Array, aber ehrlich gesagt möchte ich nicht für jeden printf()-Wert ein extra Array anlegen müssen. Ich verstehe nicht, warum es mit einem Array nicht funktionieren sollte.
Wie genau geht printf() bei der Interpretation denn vor?Zuerst werden alle 3 Funktionen aufgerufen, dann bekommt printf die 3 Ergebnisse als Parameter überreicht.
Alle nutzen den selben Buffer, also zeigen alle 3 auf den Text, in dem das Ergebnis der letzten Berechnung steht.
-
Also doch. Habs zwar vermutet, konnte es aber nicht so recht glauben.
Hat diese Vorgehensweise der Interpretation einen Vorteil?Um mal beim Punkt zu bleiben: auch wenn erst alle drei Funktionen ausgeführt werden (was logisch ist), liefert jeder Funktionsaufruf ein separates "return" und auch die übergebenden und zu verarbeitendenen Werte sind unterschiedlich.
Alle drei Funktionsaufrufe liefern also die selbe Adresse des char-Arrays in die "%s"-Makros/-bzw. Formatstrings?Logisch wäre dieses Verhalten, wenn alle drei Funktionsaufrufe parallel ausgeführt werden würden und jede Funktion zur selben Zeit in das char-Array schreiben wollte.
Aber werden die drei Funktionsaufrufe von prn_int128() in printf() nicht seriell, also nacheinander ausgeführt? Dann dürfte es doch egal sein, ob alle drei Funktionsaufrufe sich dem gleichen char-Array bedienen.Selbst wenn printf() erst nach Ausführung der drei Funktionsaufrufe das char-Array an "%s" übergibt bzw. diese anstelle dessen ersetzt, erklärt dies nicht, weshalb der Output aller drei Funktionsaufrufe in printf() dann unterschiedlich aussieht? Müsste wenn schon, nicht dann der Output jedesmal der Gleiche sein?
-
Das Array innerhalb der Funktion ist statisch, belegt also bei jedem Funktionsaufruf exakt denselben Speicher. Du rufst dreimal nacheinander die Funktion auf, die die Zahl in das Array schreibt und dessen Adresse zurückgibt. Dann rufst Du die printf-Funktion auf, die dreimal dieselbe Adresse übergeben bekommt (nämlich die von den drei Funktionsaufrufen zurückgegebene).
Spätestens an diesem Punkt müsste Dir klar werden, dass es technisch unmöglich ist, dass an dieser Adresse drei unterschiedliche Strings stehen.
-
Müsste die Ausgabe allerdings dann nicht immer die gleiche bleiben?
-
Entschuldige, ich war noch nicht bei der letzten Funktion, sondern bei der vorherigen (mit static char buf ganz oben).
Hier ist das Problem, dass die Funktion ja nicht die Anfangsadresse von testbuffer zurückgibt, sondern die Adresse des zuletzt geschriebenen Zeichens. Da 1024 zur vier Stellen lang ist, ist das die Adresse von testbuffer[36]. In testbuffer steht nach den drei Aufrufen von prn_int128 offenbar INT128_MIN (da die Aufrufreihenfolge nicht definiert ist). Und jetzt vergleiche mal die letzten vier Stellen von INT128_MIN mit Deiner Ausgabe
-
Du wirst schon getrennte Speicherbereiche zur Verfügung stellen müssen. In C99 könnte man sich wohl mit compound literals behelfen. Mal eben hingekladdet:
#include <stdio.h> char *prn_u128_aux_aux(char *dest, __uint128_t x) { char *p = dest; if(x >= 10) { p = prn_u128_aux_aux(dest, x / 10) + 1; } *p = '0' + x % 10; return p; } char *prn_u128_aux(char *dest, __uint128_t x) { prn_u128_aux_aux(dest, x); return dest; } char *prn_i128_aux(char *dest, __int128_t x) { if(x < 0) { *dest = '-'; prn_u128_aux(dest + 1, -x); } else { prn_u128_aux(dest, x); } return dest; } // Die Speicherbereiche werden hier intern beim Aufruf angelegt #define prn_u128(x) prn_u128_aux((char[64]){0}, x) #define prn_i128(x) prn_i128_aux((char[64]){0}, x) int main(void) { __int128_t x = -1234567; printf("%s %s\n", prn_i128(x), prn_i128(x)); return 0; }
Gcc kann das mit -std=c99, MSVC beherrscht C99 bislang nicht (und wird es auf absehbare Zeit auch nicht tun). Die allgemeinen Probleme mit Makros bleiben natürlich bestehen.
-
Na, ne. Das mit den PRI-Makros ist vom Tisch. Bei mir heißen sie jetzt: PRIi128, PRId128 und PRIu128. Funktioniert auch zu meiner vollsten Zufriedenheit.
seldon schrieb:
Du wirst schon getrennte Speicherbereiche zur Verfügung stellen müssen. In C99 könnte man sich wohl mit compound literals behelfen. Mal eben hingekladdet:
Was sind compound literals? Hab Google und Co. eben bemüht, jedoch mit eher schlechten Suchergebnissen.
Kannste mal bitte zu "compound literals" ein kleines Demonstrationsbeispiel machen? Ich kann mir in Bezug auf Deinen Code von eben, nicht viel darunter vorstellen.
Gibt es auch eine Möglichkeit dem GCC/g++ das ganze mit "-std=c++0x" zu verklickern?
Ziel sollte folgendes sein.
Ich möchte die 128-Bit-Integer-Typen wahlweise mit std::cout und/oder printf (C++) ODER nur mit printf() (C) verwenden können.
Es sollte zudem plattformübergreifend funktionieren (Linux, Unix, Windows). Überall dort, wo die Compiler - vorzugsweise GCC/g++ - eben diese _[u]int128_t-Typen implementiert haben. Ebenso soll bzgl. C++ bis einschließlich C++0x/11-Standard, als auch bis zum aktuellen ANSI-C-Standard unterstützt werden.Endziel soll es sein, dass man mit C oder C++ mit diesen Typen umgehen können soll, einschließlich des Outputs durch geeignete Funktionen. Da bei reinem ANSI-C kein std::cout zur Verfügung steht, entfallen damit automatisch Lösungen mit std::cout und Konsorten. Ohnehin soll es beim Einsatz von reinem ANSI-C mit den üblichen Standard-Funktionen, a´la printf() funktionieren. Während std::cout vom Tisch ist und endlich funktioniert, bleibt noch eine funktionierende C-Lösung für printf(). Diese Lösung sollte aber auch bei C++-Anwendung bis zum aktuellen C++-Standard C++0x/11 funktionieren.
Jemand Ideen, Lösungen, etc.?
Denn ich weiß nicht mehr weiter und beschäftige mich jetzt schon seit Tagen, wenn nicht sogar Wochen damit.Grüße
Schlitzauge
-
Ich nochmal. Ich bin gerade am Überlegen, ob man das auch mit dynamischen Char-Array realisieren könnte?
-
Ein "compound literal" ist ein Literal für Compound-Typen, also Structs und Arrays. Beispielsweise kann man in C99 Folgendes schreiben:
struct point { double x; double y; }; void foo(struct point p) { // ... } // ... foo((struct point) { 0.0, 0.0 });
In meinem Beispiel geht es dabei um das (char[64]){0} in
#define prn_u128(x) prn_u128_aux((char[64]){0}, x)
...womit quasi inline ein Buffer angelegt wird, der groß genug ist, um die Dezimaldarstellung eines 128-Bit-Integers aufzunehmen und lange genug vorhanden ist, um danach ausgegeben zu werden. Die Funktionen prn_i128_aux und prn_u128_aux geben einen Zeiger auf diesen Buffer zurück.
Was dynamische Buffer angeht: Die grundlegende Funktionalität kann man mit allen Arten von Buffern umsetzen, solange sie groß genug sind, aber ich sehe keine Vorteile darin, das hier dynamisch anzugehen. Dynamische Speicheranforderung ist generell langsamer, als einfach ein bisschen Kram auf den Stack zu legen, und man muss den Speicher hinterher explizit wieder freigeben. Das mögen keine riesigen Probleme sein, aber ich sehe keinen Vorteil, der es rechtfertigte, sich diese Umstände einzuhandeln.
-
Und nochmal ich.
Hab jetzt ne funktionierende C-Lösung, welche ich einfach mal prn_int128_2() genannt hab. Ich finde sie aber noch nicht ausgereift.
Wäre schön, wenn da mal jemand drüberschauen könnte:#include <climits> #include <cstdint> #include <cinttypes> #include <cfloat> #include <cwchar> #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> #include <cmath> #include <vector> #include <array> using namespace std; #define free(x) free(x); *x=NULL #define PRId128 "s" #define PRIi128 "s" #define PRIu128 "s" __int128_t INT128_MIN = (-170141183460469231731.687303715884105728) * pow(10,18); __int128_t INT128_MAX = ( 170141183460469231731.687303715884105727) * pow(10,18); const char* prn_int128_2(__int128_t x) { char *p=(char *)malloc(sizeof(char)*41); bool sign = false; bool isINT128_MIN = false; if(x == 0) { p[0] = '0'; p[1] = '\0'; return p; } if(x < 0) { sign = true; if(x == INT128_MIN) { ++x; isINT128_MIN = true; } x *= -1; } int i = 0; for(;x > 0;++i) { if(x < 10) { p[i] = '0' + (char)(x); x = 0; } else { if(isINT128_MIN == true) { p[i] = '8'; isINT128_MIN = false; } else { p[i] = '0' + (char)(x % 10); } x /= 10; } } p[i]='\0'; char buffertmp[41]={NULL}; for(int j=0;p[j]!='\0';++j) { buffertmp[j]=p[i-j-1]; } for(int k=0;buffertmp[k]!='\0';++k) { p[k]=buffertmp[k]; } if(sign == true) { for(int l=0;l<40;++l) { p[i-l+1] = p[i-l]; } p[0] = '-'; } return p; } int main(int argc, char *argv[]) { cout << "\n+Mit printf() UND prn_128_2():\n----------------------------------------------------\n"; printf("INT128_MIN:%"PRIi128"\n",prn_int128_2(INT128_MIN)); //geht printf("INT128_MAX: %"PRIi128"\n",prn_int128_2(INT128_MAX)); //geht printf("INT128: %"PRIi128"\n",prn_int128_2(0)); //geht printf("INT128: %"PRIi128"\n",prn_int128_2(1024)); //geht printf("INT128: %"PRIi128"\n",prn_int128_2(-1024)); //geht //geht: printf("INT128_MIN:%"PRIi128"\nINT128_MAX: %"PRIi128"\nINT128: %"PRIi128"\n",prn_int128_2(INT128_MIN),prn_int128_2(INT128_MAX),prn_int128_2(1024)); getchar(); return 0; }
Output (Exec):
+Mit printf() UND prn_128_2(): ---------------------------------------------------- INT128_MIN:-170141183460469231731687303715884105728 INT128_MAX: 170141183460469231731687303715884105727 INT128: 0 INT128: 1024 INT128: -1024 INT128_MIN:-170141183460469231731687303715884105728 INT128_MAX: 170141183460469231731687303715884105727 INT128: 1024
Wie Ihr seht, es funktioniert tadellos. Sowohl Zwischenwerte, wie: 0, 1024, -1024 als auch die Grenzwerte von 128-Bit-Signed-Integer.
Ebenso kann man nun die Funktion einzeln oder auch mehrfach in printf() verwenden.Was mich nun konkret stört:
- sehr viele Schleifen und IF/ELSE. (wo könnte man da vieles vereinfachen?)
- char-Array p wird dynamisch erzeugt (wie bringt man da free() nun mit ein?)
- weitere Optimierungen & Kritiken sind gerne willkommenGrüße
Schlitzauge
-
Haha. Das ist nicht dein Ernst, oder?
-
???
Naja, es funktioniert und ich sagte doch auch, dass ich die Lösung noch nicht perfekt finde. Ich wäre natürlich lieber an einer statischen Lösung interessiert, aber die einzige statisch funktionierende Lösung hier, setzt GCC/g++ mit "-std=c99" voraus. Ich verwende aber "-std=c++0x" und möchte auch dabei bleiben.
-
Du leckst Speicher wie ein Küchensieb; ich würde das nicht als "funktioniert tadellos" bezeichnen.
Die Frage ist ein bisschen, was du eigentlich willst. Die grundlegende Funktionalität lässt sich auf verschiedene Arten umsetzen; schwierig ist allein der syntaktische Zucker. Du wirst printf keine neuen Format-Spezifikatoren beibringen können, und in C89 wirst du einen Aufruf der Form printf("%s\n", prn_i128(x)); auch nicht kriegen. Für C++ und C99 habe ich dir bereits Code gegeben.
Der dynamische Ansatz ist hier nicht wirklich sinnvoll - wenn du den syntaktischen Zucker aufweichst und einen weiteren Parameter mitgibst, um den Zeiger aufzunehmen und nachher freizugeben, kannst du genau so gut einen Zeiger auf einen Buffer auf dem Stack mitgeben. Mehr als das ist wohl nicht drin.
-
Deine Lösung ist ja auch nicht schlecht, ganz im Gegenteil. Aber sie lässt sich bei mir mit "-std=c++0x" einfach nicht übersetzen und zweigleißig was Compiler- sowie Compiler-Optionen betrifft, wollte ich dann doch nicht fahren.
Wenn Du mir noch sagen könntest, wie man Deine letzte Lösung auch im C++0x-Mode übersetzen und nutzen könnte, wärs ja perfekt.Ebenso wüsste ich gerne, wie ich meine Lösung statisch gestalten kann, ohne das man für jeden Aufruf ein extra char-Array benötigt.
Mit "funktioniert tadellos" bezog ich mich ausschließlich auf die Ausgabe und die funktioniert nunmal tadellos, egal welche Werte ich mitgebe. Ich würde nur gerne die dynamisch erzeugten char-Array´s (p´s) wieder freigeben lassen. Nur wie?
-
Komm von printf weg, oder lebe mit den Einschränkungen.
-
314159265358979 schrieb:
Komm von printf weg, oder lebe mit den Einschränkungen.
Wie oft denn noch? Habe ich einen C++-fähigen Compiler, nehme ich std::cout, keine Frage.
std::cout oder andere C++-Elemente funktionieren nunmal aber nicht bei reiner C-Anwendung.
Wie dem auch sei. Wenn jemand noch weiter weiß, kann er/sie es ja gerne hier posten. Ebenso wäre ich sehr dankbar für Vereinfachungen und Optimierungen meiner dynamisch gestalteten Lösung. Besser eine, als keine.
Es geht ja auch darum, die Grenzen des "Möglichen" neu zu entdecken.
-
Schau auf Seite 4 dieses Threads, dritter Beitrag von unten; das kriegst du auch durch einen C++-Compiler. Danach halt
#ifdef __cplusplus // C++-Code #else // C-Code #endif
...und in Dreckiger-Hack-Land ist alles wieder in Butter.
Dass du C99-Code durch einen C++-Compiler nicht durchjagen kannst, ist nicht weiter verwunderlich - schließlich handelt es sich bei C und C++ um verschiedene Sprachen, und wo C++98 von C89 noch viel übernommen hat, ist das bei C99 nicht der Fall.
-
Schlitzauge schrieb:
Wie oft denn noch? Habe ich einen C++-fähigen Compiler, nehme ich std::cout, keine Frage.
Was du nicht sagst.
Schlitzauge schrieb:
std::cout oder andere C++-Elemente funktionieren nunmal aber nicht bei reiner C-Anwendung.
Dann lebe mit den Einschränkungen.
Schlitzauge schrieb:
Wie dem auch sei. Wenn jemand noch weiter weiß, kann er/sie es ja gerne hier posten. Ebenso wäre ich sehr dankbar für Vereinfachungen und Optimierungen meiner dynamisch gestalteten Lösung. Besser eine, als keine.
seldon hat dir bereits geholfen so gut es geht. Einerseits möchtest du eine C-printf Lösung, andererseits soll es mit C++0x kompilierbar sein. Das ergibt keinen Sinn.
Schlitzauge schrieb:
Es geht ja auch darum, die Grenzen des "Möglichen" neu zu entdecken.
Da gibts nix neu zu entdecken, wir können programmieren. Die bestmöglichen Lösungen hast du bekommen, es _geht_ nicht besser.
Und ganz ehrlich gesagt bezweifle ich bei deinen Kenntnissen auch mal stark, dass du den Typen brauchst.
@seldon: Selbe Sekunde, nice