Seite 1 von 1

[GCC] itoa()-Derivate

Verfasst: 26.11.2010, 22:25
von Krishty
Hi,

Kann mir jemand, der mit GCC Erfahrung hat, sagen, was die C-Runtime für Funktionen anbietet, um Ganz- und Gleitkommazahlen in Strings zu schreiben? Ich finde im Netz nur ominöse Hinweise, dass es mit 3.4 noch einfach so ging oder dass man sowas gar selber schreiben sollte …

… also, direkte Funktionen für Zahlen mit acht bis 64 Bits in statische Puffer zur Basis zehn und 16. Keine printf()- oder stringstream-Derivate, die ja entweder keine 64-Bit-Ganzzahlen oder andere Basen als zehn unterstützen, dynamischen Speicher allokieren oder saulangsam sind – eben die Gegenstücke zu _ultoa_s(), _itoa_s(), _ui64toa_s(), _i64toa_s() und _gcvt_s() aus Visual C++’ C-Runtime.

Gruß, Ky

Re: [GCC] itoa()-Derivate

Verfasst: 27.11.2010, 00:30
von Sternmull
Eine fertige Lösung hab ich nicht parat. Für Integer ist eine eigene Implementierung aber schnell gemacht. Für Gleitkommazahlen würde ich mir das allerdings nicht zutrauen. Vor Kurzem hatte ich mal gesucht was es da Fertiges gibt und hab mir letzten Endes diese Implementierung hier vorgemerkt. Die gute Nachricht: Die Lizenz ist brauchbar. Die schlechte Nachricht: Ich habs bisher selber nicht ausprobiert und weiss nicht ob der Code brauchbar ist. Besteht aus Unmengen #if #endif. Ich hoffe mal das man die Allkationen auf alloca umbiegen kann. Bin an Erfahrungsberichten oder einer besseren Möglichkeit interessiert :)

Mich hat primär die Locale-Abhängigkeit der Standardfunktionen motiviert mich nach Alternativen umzusehen. Außerdem ging es mir in erster Linie um die andere Richtung. Dazu findet sich z.B. hier eine brauchbare Lösung (die allerdings Integer Overflows ignoriert!). Möglicherweise hast du dafür ja in dem zusammenhang auch Verwendung.

Re: [GCC] itoa()-Derivate

Verfasst: 27.11.2010, 14:23
von Krishty
Toll.

Das kann doch nicht sein, dass eine Laufzeitbibliothek so was Grundlegendes nicht zur Verfügung stellt?! Womit arbeiten denn deren ::sprintf() und ::std::ostream intern?!
Ich kriege schon wieder so eine Wut auf die GCC-Ecke …

Aber danke für die Links – wenn es hart auf hart kommt, implementiere ich das echt wie in den Links.

Re: [GCC] itoa()-Derivate

Verfasst: 27.11.2010, 16:13
von eXile
Krishty hat geschrieben:Das kann doch nicht sein, dass eine Laufzeitbibliothek so was Grundlegendes nicht zur Verfügung stellt?! Womit arbeiten denn deren ::sprintf() und ::std::ostream intern?!
Ich kriege schon wieder so eine Wut auf die GCC-Ecke …
So wie ich grade durch den Code gestapft bin, würde ich sagen, die GNU libc benutzt die GNU libio dafür. Hier die entsprechende Funktion, die dabei die ganze Arbeit macht (für sprintf würde für fp ein String-File übergeben werden, also wundere dich nicht darüber, dass die zusammenarbeiten können). Am interessantesten müsste für dich dann __cvt_double sein, weil das in einen hinreichend großen Speicherbereich genau den übergebenen double-Wert dort als String reinschreibt.

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 00:09
von BeRsErKeR
strtol (String -> long)
strtoul (String -> unsigned long)
strtod (String -> double)

Hat mich ca 2 Sekunden in der C-Library Doku gekostet.

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 01:57
von eXile
Um deine Euphorie zu bremsen:
Krishty hat geschrieben:... um Ganz- und Gleitkommazahlen in Strings zu schreiben
Und es geht vor allen Dingen darum, dass man das in einen statisch allokierten String fester Größe schreiben will, da ja die maximale float- oder double-Stringrepräsentation eine fixe Länge besitzt.

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 11:45
von Krishty
eXile hat geschrieben:So wie ich grade durch den Code gestapft bin, würde ich sagen, die GNU libc benutzt die GNU libio dafür. Hier die entsprechende Funktion, die dabei die ganze Arbeit macht (für sprintf würde für fp ein String-File übergeben werden, also wundere dich nicht darüber, dass die zusammenarbeiten können). Am interessantesten müsste für dich dann __cvt_double sein, weil das in einen hinreichend großen Speicherbereich genau den übergebenen double-Wert dort als String reinschreibt.
Achtung, Anfängerfrage: Ich habe auf meinem Windows Code::Blocks mit MinGW installiert. Welche C-Laufzeitbibliothek wird GCC nun linken? Ich kann nämlich nirgends in meiner Installation eine Datei finden, die auf „libc“ schließen würde, geschweige denn eine Referenz zu __cvt_double() :(

Vorerst habe ich überall snprintf() hingehauen. Unter GCC steht mir dank C99 ja immerhin das ll-Postfix zur Verfügung, um 64-Bit-Zahlen ausgeben zu können … das klappt logischerweise nur im C++0x-Modus, aber ich werde immer unsicherer, ob ich C++98 bei dem ganzen Geraffel überhaupt noch weiter unterstützen will.

@BeRsErKeR: Ja, es geht mir genau um die andere Richtung.

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 13:02
von kimmi
Wie wäre es mit depends? Da sollte doch die Runtime-Dll, sofern als Dll vorhanden, in der Dependency-Liste angezeigt werden.

Gruß Kimmi

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 13:19
von Aramis
Das kann doch nicht sein, dass eine Laufzeitbibliothek so was Grundlegendes nicht zur Verfügung stellt?! […]
Ich kriege schon wieder so eine Wut auf die GCC-Ecke …
Ich wuerde an deiner Stelle meine Wut lieber gegen das Standard-Komitee richten. „Die GCC-Ecke” macht es im Grunde genommen richtig, davon abgesehen dass sie nicht alles symetrisch zur MSVC-Implementierung aufziehen. Aber das will man ihnen ja nicht vorwerfen, oder? :-)

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 13:57
von Krishty
Klar, in erster Linie geht die Wut gegen das Standardkommittee. Aber ganz in Unschuld kann sich GCC die Hände auch nicht waschen -- die round()- und trunc()-Funktionen stellen sie sogar im ANSI-only-Modus zur Verfügung, obwohl sie nicht Teil des Standards sind, und weigern sich, sie wieder rauszunehmen. Diese Bigotterie hat mich vor laaaanger Zeit, als ich von GCC auf Visual C++ umgestiegen bin (kaum zu glauben, aber angefangen habe ich vor tausend Jahren auf GCC) schon Haare gekostet ... quasi selbe Sache wie heute: Ich war schockiert, dass mir so grundlegende Funktionen nicht zur Verfügung gestellt werden.

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 19:10
von BeRsErKeR
eXile hat geschrieben:Um deine Euphorie zu bremsen:
Krishty hat geschrieben:... um Ganz- und Gleitkommazahlen in Strings zu schreiben
Und es geht vor allen Dingen darum, dass man das in einen statisch allokierten String fester Größe schreiben will, da ja die maximale float- oder double-Stringrepräsentation eine fixe Länge besitzt.
Ups da hab ich mich wohl verlesen.


@Krishty: Mal ehrlich, wozu brauch ich itoa wenn es sprintf oder stringstreams gibt. Das bischen an Overhead wird man heutzutage wohl verkraften können. sprintf kann auch 64Bit-Werte und die Basen 10 und 16. stringstreams können auch die beiden Basen, ob 64Bit-Werte, weiß ich grad nicht. Ich habe itoa noch nie gebraucht und es auch ehrlich gesagt nicht vermisst.

Re: [GCC] itoa()-Derivate

Verfasst: 29.11.2010, 19:24
von Krishty
BeRsErKeR hat geschrieben:@Krishty: Mal ehrlich, wozu brauch ich itoa wenn es sprintf oder stringstreams gibt. Das bischen an Overhead wird man heutzutage wohl verkraften können. sprintf kann auch 64Bit-Werte und die Basen 10 und 16. stringstreams können auch die beiden Basen, ob 64Bit-Werte, weiß ich grad nicht. Ich habe itoa noch nie gebraucht und es auch ehrlich gesagt nicht vermisst.
Ja, sprintf() ist eine Möglichkeit, wenn auch eine für meinen Geschmack etwas zu Schwere. Benutze ich jetzt ja auch – aber 64-Bit-Ganzzahlen gehen eben nur unter C99 und C++0x. Gegen stringstream spricht, dass ich keinen Speicher allokieren darf und der Overhead gemessen an der Aufgabe wirklich zu groß ist.

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 00:17
von BeRsErKeR
Hab nen lustigen Code dazu gefunden und ihn ein wenig erweitert:

Code: Alles auswählen

char* itoa(int value, char* str, int base, int size)
{
    if(!value)
    {
        str[0] = '0';
        str[1] = '\0';
        return str;
    }

    static char buf[32] = {0};
    bool sign = value < 0;

    if(sign)
        value = -value;

    int i = std::min(size, 31);

    for(; value && i; value /= base)
        buf[--i] = "0123456789abcdef"[value % base];

    if(sign && i)
        buf[--i] = '-';

    memcpy(str, &buf[i], std::min(size, 32-i));

    return str;
}
Aufruf dann z.B. so:

Code: Alles auswählen

char str[20];
itoa(500, str, 10, 20);

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 01:05
von Krishty
Ja – lustig ist vor allem das Verhalten, wenn der kleinste negative Wert übergeben wird (im Zweierkomplement ist eine negative Zahl mehr darstellbar als Positive, value = -value bleibt negativ und damit ist "0123456789abcdef"[value % base]; undefiniert. Also wird es im besten Fall vom Optimizer durch = 0 ersetzt, im Schlimmsten stürzt es zur Laufzeit ab).

Außerdem sorgt das static vor dem Puffer dafür, dass der Puffer nur beim ersten Mal mit 0 initialisiert wird und bei späteren Aufrufen die Reste der vorherigen Zahlen in der Ausgabe landen, wenn man dabei die Puffergröße verringert.

Ich wette, da stecken noch zwei oder drei weitere solcher Dinger drin, die hier keinem von uns auffallen, bevor es nicht knallt. Und genau deshalb will ich es nicht selber schreiben, sondern – wie im Fall von Microsofts Laufzeitbibliothek – bis zum Erbrechen getestete, bewährte, verifizierte, vorgefertigte Funktionen.

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 01:23
von BeRsErKeR
Soweit ich gesehen habe wird das bei so ziemlich jeder itoa-Implementierung mit value = -value gemacht. Wäre ja mal interessant das bei der Visual Studio Implementierung zu testen.

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 01:26
von Krishty
Funktioniert.

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 01:48
von Schrompf
Das Beispiel knallt außerdem im Multithreaded-Betrieb, weil die Funktion ohne Not mit einem static buffer arbeitet. Wenn man eh einen Zielspeicher angeben muss und selbst dafür sorgen muss, dass er groß genug ist - warum dann der Umweg über den internen Zwischenpuffer?

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 02:10
von BeRsErKeR
Wie gesagt, das Beispiel sollte nicht als Lösung dienen. Ich fand die Implementierung optisch nur sehr amüsant. Der static buffer ist meiner Meinung nach deshalb vorhanden, weil der erzeugte String in der Regel kürzer ist als die Größe des Buffers und man in dem Fall nicht die Startaddresse des Buffers zurückgibt. Das Verfahren baut den String ja von hinten nach vorn auf und daher wären sonst die vorderen Zeichen leer bzw mit unnötigem Inhalt belegt. Klar wäre schon deshalb ein Verfahren besser, welches den String von vorn nach hinten aufbaut. Ich glaube in der Regel wird ein string-reverse ausgeführt nachdem die Zahl in umgedrehter Ziffernreihenfolge in den Buffer gelegt wurde.

Re: [GCC] itoa()-Derivate

Verfasst: 30.11.2010, 10:10
von Krishty
BeRsErKeR hat geschrieben:Das Verfahren baut den String ja von hinten nach vorn auf und daher wären sonst die vorderen Zeichen leer bzw mit unnötigem Inhalt belegt. Klar wäre schon deshalb ein Verfahren besser, welches den String von vorn nach hinten aufbaut. Ich glaube in der Regel wird ein string-reverse ausgeführt nachdem die Zahl in umgedrehter Ziffernreihenfolge in den Buffer gelegt wurde.
Ja, ein Reversal macht Microsofts Implementierung auch. Rein vom Konzept her habe ich auch nichts gegen einen funktionsinternen Puffer … hier glaube ich aber eher, dass jemand die Bedeutung von static nicht verstanden hat.