2015-12-15 14 views
5

Ich möchte mehrere Zahlen in eine Darstellung konvertieren und dann die Flags, Breite und Genauigkeit von *printf() Spezifizierer verwenden. Vorzug wäre, globale oder static Puffer zu vermeiden. Das Hauptproblem scheint darin zu bestehen, wie man für jede der umgewandelten Zahlen einen char[] bereitstellt?Wie verwenden Sie zusammengesetzte Literale zu `fprintf()` multiple formatierte Zahlen mit beliebigen Basen?

fprintf(ostream, "some_format", foo(int_a, base_x), foo(int_b, base_y), ...); 

Wie C11 Verbindung Literale verwenden, um dies zu lösen?
Wie verwendet man C99 (oder später) zusammengesetzte Literale, um dies zu lösen?

+0

Warum nur C11? Es würde auch auf/mit C99 anwendbar/lösbar sein. – alk

+0

meinst du, du willst '% s' anstelle von'% d' oder was auch immer benutzen? –

+0

@ M.M Verwenden Sie '"% s "' oder '"% d "' oder was auch immer. Ich möchte keine Romanideen ersticken. – chux

Antwort

13

C99 C11 eingeführt Verbindung Literale was eine komplizierte Struktur initialisiert nicht nur ermöglichen, sondern auch eine "in-line" Variable.

-Code eine Konvertierungsfunktion und geben in einem neuen Puffer (char [UTOA_BASE_N]){0} pro jedem Funktionsaufruf aufrufen kann die Funktion ermöglicht, dass die gleichen Puffer zurück, jetzt nach Bedarf geschrieben, dass noch innerhalb ihrer Lebensdauer ist. Die zurückgegebene Zeichenfolge wird dann unter Verwendung verschiedener Flags, Breite und Genauigkeit gedruckt, die für den Spezifizierer "%s" verfügbar sind.

#include <stdio.h> 
#include <stdlib.h> 
#include <limits.h> 

// Maximum buffer size needed 
#define UTOA_BASE_N (sizeof(unsigned)*CHAR_BIT + 1) 

char *utoa_base(char *s, unsigned x, unsigned base) { 
    s += UTOA_BASE_N - 1; 
    *s = '\0'; 
    if (base >= 2 && base <= 36) { 
    do { 
     *(--s) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[x % base]; 
     x /= base; 
    } while (x); 
    } 
    return s; 
} 

#define TO_BASE(x,b) utoa_base((char [UTOA_BASE_N]){0} , (x), (b)) 

void test(unsigned x) { 
    printf("base10:%10u base2:%5s base36:%s ", x, TO_BASE(x, 2), TO_BASE(x, 36)); 
    printf("%lu\n", strtoul(TO_BASE(x, 36), NULL, 36)); 
} 

int main(void) { 
    test(0); 
    test(25); 
    test(UINT_MAX); 
} 

Ausgabe

base10:   0 base2: 0 base36:0 0 
base10:  25 base2:11001 base36:P 25 
base10:4294967295 base2:11111111111111111111111111111111 base36:1Z141Z3 4294967295 

Ref: Is there a printf converter to print in binary format? hat eine Reihe von Antworten, aber keiner von ihnen erlaubt die einfache Speicherverwaltung (keine static) der oben mit Zugang zu fprintf() Flaggen Breite, Präzision und verwendet die vollständige Reichweite der Nummer.

Dies ist eine Answer your own question Antwort.

+1

Hinweis: Ich bestätige, dass der Rückgabewert immer noch im Gültigkeitsbereich liegt, weil "... seine Lebensdauer vom Eintrag in den Block, mit dem er verknüpft ist, bis zur Ausführung dieses Blocks in irgendeiner Weise endet." (Eingeben eines geschlossenen Blocks oder Aufrufen einer Funktion) unterbricht die Ausführung des aktuellen Blocks, beendet sie aber nicht.) "C11dr §6.2.4 6 – chux

+0

@chux: Ich denke, Sie haben Recht, aber Umfang und Lebensdauer sind unterschiedliche Konzepte. Ein Objekt hat eine Lebenszeit; Ein Bezeichner hat einen Gültigkeitsbereich. Im Gegensatz zu Lebenszeiten können Bereiche nicht zusammenhängend sein. – rici

+0

Ein Beispiel, bei dem Umfang und Lebensdauer radikal verschieden sind: 'void f (void) {statisch int x = 42; } ' – rici