Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 50 di 93
  • livello avanzato
Indice lezioni

Formattazione e Localizzazione

Utilizzare le opzioni messe a disposizione dal linguaggio di programmazione C++ per la formattazione dello stream di output e la sua localizzazione.
Utilizzare le opzioni messe a disposizione dal linguaggio di programmazione C++ per la formattazione dello stream di output e la sua localizzazione.
Link copiato negli appunti

La Standard Stream Library di C++ si differenzia in modo netto dall'approccio adottato dalle API del linguaggio C anche per ciò che riguarda la formattazione.

Poichè il particolare data model su sui essa è basata fa uso della programmazione orientata agli oggetti, le opzioni di formattazione sono definite come dati membro delle istanze dei flussi di I/O. Quindi, anche il modo in cui vengono rappresentati i dati che in essi transitano concorre a definire lo stato di tali oggetti.

Esistono due modi equivalenti per applicare le preferenze per la formattazione. Il primo consiste nell'uso di apposite funzioni membro degli oggetti stream. Il secondo fa ricorso a funzioni esterne dette manipolatori di flusso che possono essere usate unitamente agli operatori di estrazione (>>) e di inserimento (<<), definiti rispettivamente per i canali di input e di output.

Uso di funzioni membro per la formattazione

La maggior parte delle opzioni di formattazione disponibili è immagazzinata sotto forma di una semplice maschera binaria in cui ogni bit è associato ad una particolare impostazione.

La definizione della classe std::ios_base, che è base comune per le classi da cui si istanziano ad esempio i canali standard std::cin e std::cout, include alcune funzioni membro che consentono di manipolare singolarmente i bit di tale maschera modificandone lo stato da "acceso" a "spento", e viceversa.

È poi disponibile un insieme di funzioni membro per la configurazione delle impostazioni parametriche, quali la precisione aritmetica, l'ampiezza del campo, il carattere di riempimento, etc.

Un esempio dell'uso di queste API è fornito nel listato seguente:

#include <iostream>
#include <cmath>
int main()
{
std::cout.setf(std::ios_base::scientific);
std::cout << "Pi greco in notazione scientifica: " << M_PI<< '\n';
std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
std::cout.precision(15);
std::cout << "Pi greco in notazione fixed-point e 15 cifre di precisione: " << M_PI << '\n';
return 0;
}

Le opzioni di formattazione std::ios_base::scientific e std::ios_base::fixed riguardano la visualizzazione di valori in virgola mobile e ricadono nell'insieme di impostazioni non parametriche, cioè quelle che possono solo essere attivate o disattivate.

In questo esempio, l'invocazione della funzione membro setf(std::ios_base::scientific) "accende" il bit per la notazione scientifica, mentre la successiva invocazione di un sovraccarico di questo metodo con i parametri std::ios_base::fixed e std::ios_base::floatfield "accende" il bit della notazione fixed-point e contemporanemente spegne quello della notazione scientifica, effettuando un'operazione bit a bit con il valore std::ios_base::floatfield che rappresenta la maschera binaria che contiene l'opzione predefinita del linguaggio per la visualizzazione dei valori in virgola mobile. L'istruzione successiva, al contempo, imposta il numero di cifre decimali da visualizzare dopo la virgola.

Manipolatori di flusso

I manipolatori di flusso sono particolari funzioni che consentono di adottare una sintassi uniforme a quella usata per l'immissione o l'estrazione di dati da un canale anche per le opzioni di formattazione.

Ciò è possibile perchè esistono appositi sovraccarichi degli operatori di inserimento o estrazione nelle classi stream che accettano tali funzioni come argomenti.

Ad esempio, il listato seguente è equivalente al precedente, ma fa uso di manipolatori invece che di funzioni membro:

#include <iostream>
#include <iomanip>
#include <cmath>
int main()
{
std::cout << "Pi greco in notazione scientifica: "
<< std::scientific << M_PI << std::endl;
std::cout << "Pi greco in notazione fixed-point e 15 cifre di precisione: "
<< std::setprecision(15) << std::fixed << M_PI << std::endl;
return 0;
}

La dichiarazione dei manipolatori di flusso è parte del namespace std ed è suddivisa in vari header files, ad esempio setprecision(int) ed in generale tutti i manipolatori di flusso parametrici sono definiti nel file <iomanip>

In questo caso, al posto del carattere \n si usa il manipolatore endl per forzare l'andata a capo ed il contestuale flush del canale.

Il valore restituito delle funzioni manipolatori è un riferimento allo stream: ciò rende di fatto possibile concatenare molteplici operazioni di inserimento / estrazione e di formattazione dando l'illusione che la transitabilità del canale sia estesa anche alle opzioni di formattazione, oltre che ai dati. Nella maggiorparte dei casi, ciò conferisce una maggiore leggibilità e compattezza del codice.

Opzioni di formattazione e localizzazione

Tra le numerose opzioni di formattazione, la maggior parte sono relative alla rappresentazione di dati numerici. Alcune sono generiche, altre sono invece legate al fatto che il valore numerico sia intero o in virgola mobile.

Ad esempio, per tipi interi esistono opzioni per la base di riferimento (decimale, ottale, esadecimale) e l'uso di un prefisso specifico (0 per i valori ottali, 0x per quelli esadecimali) che si applica solo nel caso in cui essa non sia la base decimale. Per i valori booleani è possibile scegliere se usare 0 e 1 o le stringhe true e false.

Per i numeri in virgola mobile esistono opzioni che consentono di cambiare il numero di cifre decimali, mostrare il segno anche per i numeri positivi e l'uso di lettere maiuscole o minuscole per la notazione scientifica.

Esistono poi opzioni che riguardano il massimo numero caratteri, l'allineamento, il carattere di riempimento per tutti i dati che hanno una rappresentazione basata su ampiezza fissa, che si applicano indipendentemente dal tipo.

Infine esistono opzioni specifiche che non riguardano la formattazione, ma regolano il comportamento del canale sottostante. Ad esempio alcune opzioni consentono di ignorare gli spazi che precedono un dato, di effettuare il flush del buffer in un momento specifico per i canali di output, o di rendere automatico il flush dopo ogni operazione di inserimento.

Per una trattazione completa di tutte le possibili opzioni si rimanda alla documentazione del linguaggio. In questa sede è importante osservare che, data l'uniformità delle API della libreria, tali opzioni non si applicano solo all'interazione mediante riga di comando, ma si estendono a tutte le classi di flusso che si interfacciano a dispositivi sorgente o destinazione differenti, ad esempio la memoria centrale ed il file system, come vedremo nelle lezioni successive.

Un'ulteriore considerazione in merito alla formattazione e rappresentazione dei dati è quella relativa alla localizzazione, cioè l'insieme di convenzioni linguistiche cui la nostra applicazione deve uniformarsi per soddisfare un requisito funzionale.

Nel listato seguente, ad esempio, si mostra come sia possibile selezionare il separatore per le cifre decimali dei numeri in virgola mobile in base alla lingua italiana per la quale si usa la virgola, e quella per l'inglese americano, dove si usa il punto:

#include <iostream>
#include <iomanip>
#include <cmath>
#include <locale>
int main()
{
std::locale it("it_IT");
std::cout.imbue(it);
std::cout << "Uso della virgola come separatore: " << M_PI << '\n';
std::locale us("en_US");
std::cout.imbue(us);
std::cout << "Uso del punto come separatore: " << M_PI << '\n';
return 0;
}

Per le opzioni di localizzazione dei canali di I/O si fa uso della funzione membro imbue() che accetta come parametro un oggetto di tipo locale. Il costruttore di tale oggetto ha come argomento una stringa identificativa di una tra le varie configurazioni predefinite del sistema.

In modo del tutto analogo si può selezionare una convenzione linguistica particolare anche per i canali di input per facilitare l'immissione dei dati da parte dell'utente o da una sorgente alternativa, ad esempio un file.

Ti consigliamo anche