Opzioni alternative per la formattazione delle stringhe in C ++?

7

Sto cercando di ottimizzare alcuni codici di formattazione delle stringhe che sono molto colpiti dal nostro codice. Stavamo usando ostringstream e ho convertito il codice per usare sprintf (in realtà sprintf_s più sicuri di Microsoft). Ho scambiato la sicurezza del tipo per le prestazioni in fase di esecuzione. Ma ho eseguito il debug di abbastanza strani incidenti relativi allo sprintf per sapere che sprintf ha i suoi gravi difetti che il controllo del tempo di compilazione di ostringstream cattura. Ma l'ostruzionismo è più di un ordine di grandezza più lento di quanto non lo sia con la mia misura, e non è tollerabile in questo codice. Inoltre, non sono entusiasta della leggibilità della formattazione della stringa di flusso C ++, ma potrebbe essere del tutto soggettiva.

Quindi sfortunatamente durante la formattazione delle stringhe in C ++ ho diverse opzioni "standard" che non sono ottimali:

  1. sprintf: veloce, ma non sicuro. Può avere bug insidiosi quando non viene utilizzata la stringa di formato errata.
  2. ostringstream: lento, ma digita sicuro. IMO Brutto, troppo prolisso e difficile da leggere.
  3. boost :: format - un po 'più leggibile di Ostringstream IMO, ma nei miei benchmark delle prestazioni sembra essere più lento quindi ostringstream, quindi questo è fuori.

Per riassumere, non sono davvero soddisfatto delle opzioni "standard". Mi piacerebbe qualcosa che prendesse sul serio sia le prestazioni che il tipo di sicurezza. Quali altre opzioni di formattazione delle stringhe sono disponibili per C ++?

    
posta Doug T. 21.12.2011 - 17:28
fonte

5 risposte

4

Raccomando questa libreria di formattazione che ho scritto di recente. Ecco un elenco incompleto delle sue caratteristiche:

È una nuova libreria, ma supporta già quasi tutte le opzioni di formattazione di (s)printf (con diversa sintassi), oltre a supportare argomenti posizionali, allineamento centro, carattere di riempimento personalizzato e tipi definiti dall'utente.

Aggiornamento: ora fornisce anche un'implementazione sicura printf

    
risposta data 30.12.2012 - 06:00
fonte
3

Questa non è una risposta completa, suppongo, dato che le prestazioni sono importanti - scalare sprintf potrebbe essere un punto di partenza migliore.

Un'area in cui è necessario esaminare è come funziona GCC. Fondamentalmente, anche se C (e C ++) non si preoccupano di usare il linguaggio typececk di% d e di avere realmente interi sui rispettivi argomenti, in genere GCC lo rileva sempre e fornisce Warnings . In realtà puoi trattare l'avviso come errore con le opzioni -Werror . Il punto è che in sostanza GCC fa già una verifica di "tipo sicurezza" in fase di compilazione. Questo è esattamente ciò di cui hai bisogno.

    
risposta data 21.12.2011 - 18:30
fonte
1

Sono stato richiamato qui dopo aver scritto il mio printf-like Al momento, l'helper in formato sicuro per la revisione su CR [link] . Mi stavo chiedendo alternative migliori e mi sono trovato a pensare in modo troppo concettuale che sembra essere più adatto qui che in CR.

Problema di sicurezza del tipo di snprintf

Il suffisso n o Microsoft _s può proteggere dall'overflow del buffer e molti-built-in-args-check di molti compilatori possono proteggere da altri errori (come argomenti non sufficienti), ma comunque, ci sono alcuni angoli casi. Il problema è in va_list , in cui tutti i tipi vengono cancellati e la trasmissione viene eseguita in base a specificatori di testo all'interno della stringa di formato. Un altro problema è che non è possibile passare oggetti (le classi non banali e anche i wrapper struct / POD sono un problema). Non si tratta di sicurezza del tipo ma di facilità di utilizzo.

Alternative a va_list

I modelli Variadic sono la soluzione e possono essere utilizzati per produrre formattatori veramente veloci. Un'altra cosa che ho attualmente in mente è usare il nuovo C ++ 11% diliterals, ad es. operator "" _fmt(const char *str, size_t len) che potrebbe verificare le opzioni di formattazione specifiche e selezionare l'implementazione più veloce (soprattutto quando non vengono utilizzati argomenti posizionali). C ++ 14 ha inoltre rimosso la necessità di funzioni constexpr a dichiarazione di ritorno, che possono essere eseguite in modo più elegante.

Questo buf << "hello %s! pi = %g :)"_fmt("world", 3.14159265) potrebbe essere la forma definitiva per un'alternativa rapida e sicura per il tipo che ho in mente. Potrebbe essere reso davvero molto veloce con poche specializzazioni template.

Boost :: format e ostream

Entrambi sono mostruosi all'interno, boost :: format ancora di più, ma sono sicuri per il tipo, estensibili e con pochi trucchi che coinvolgono modelli variadici e specializzazioni, potrebbe essere reso più veloce. Come li hai messi a confronto? snprintf è per i buffer, ostream è per gli stream, ostringstream per le stringhe, che è più complesso. L'idea alla base è probabilmente quella di rendere qualcosa di universale e funzionante, che servirebbe allo scopo. Di solito la velocità non è così critica in questi giorni, la selezione dell'algoritmo (ad es. O (n ^ 2) contro O (n log n)) è spesso più importante di quanto O (1) impiegherà davvero.

Veloce vs universale

La soluzione più veloce sarebbe sempre quella di scrivere la tua versione specializzata per ogni tipo di stringa di formato. Niente può battere quello. Quindi, la domanda è: quanto vicino / lontano vuoi andare?

Sono un programmatore di firmware e IAR EWARM offre opzioni circa prinf e scanf di implementazione - in genere alcuni di base (ad esempio no hex-floats) vs. full. Questo chiaramente riguarda la scelta della potenza rispetto alla velocità (e alle dimensioni).

    
risposta data 05.10.2014 - 15:40
fonte
1

Gli stream sono molto lenti perché hanno un'implementazione relativamente inefficiente, e anche perché hanno un bel po 'di overhead campane e fischietti che non hai davvero bisogno. Fondamentalmente, servono allo scopo preciso di cui hai bisogno.

La domanda, in definitiva, riguarda esattamente lo sforzo a cui sei disposto ad andare e il numero di tipi che stai trasmettendo. sprintf non è solo non sicuro, è anche completamente inestendibile, qualcosa che non è vero per ostringstream . Puoi anche utilizzare modelli di espressioni per migliorare le sue prestazioni. Il problema di rendimento di ostringstream non è affatto endemico per il suo design.

    
risposta data 21.12.2011 - 18:55
fonte
0

Sospetto che tu stia cercando un proiettile d'argento. È davvero un triangolo, (veloce, potente, sicuro). Hai bisogno di velocità, quindi la tua unica scelta è potente o sicura, non puoi averli entrambi. sprintf è veloce e potente, a scapito della sicurezza.

Dovresti essere in grado di avvolgere sprintf in modi che limitano il suo utilizzo (rendendolo meno potente, più sicuro), e nonostante i controlli del tempo di esecuzione e la rigorosa revisione del codice, assicurati che le tue prestazioni e gli obiettivi di sicurezza siano soddisfatti. Se questo non può essere raggiunto, pensa attentamente perché non prima di scegliere un'altra opzione.

    
risposta data 21.12.2011 - 22:52
fonte

Leggi altre domande sui tag