mercoledì 21 novembre 2018

C e C++: Appunti di una riscoperta 7

Le costanti in C possono essere carattere, in virgola mobile o intere.

Le costanti carattere sono rappresentate appunto da un carattere racchiuso tra due apici:

char c1 = 'A';
char c2 = '5';

Ricordiamo ancora una volta che in questo caso char non contiene il glifo del carattere tra apici ma un valore numerico mappato nella tavola ASCII. Per cui nel caso di 'A' c1 vale 65 e nel caso del '5' c2 vale 53. Quindi facciamo attenzione a non confondere il '5' costante carattere con il 5 costante numerica.


Oltre ai caratteri, simboli e numeri, sono caratteri singoli anche le combinazioni di escaping che sono
  • \a - segnale acustico
  • \b - back space
  • \f - form feed o modulo continuo ha senso per le stampanti e non per lo schermo
  • \n - nuova riga
  • \r - ritorno carrello
  • \t - tabulazione orizzontale
  • \v - tabulazione verticale, anche questa ha senso per le stampanti e non per il monitor
  • \' - apice singolo
  • \" - apice doppio
  • \\ - back slash
  • \? - punto interrogativo
  • \ooo - un qualunque valore di un carattere espresso in ottale (3 cifre)
  • \xhh - un qualunque valore di un carattere espresso in esadecimale (2 cifre)
Esempi per ottale e esadecimale:

char c1 = 'A';
char c2 = '\101';
char c3 = '\x41';

In tutti i casi il contenuto delle variabili è il valore 65 corrispondente nella tavola ASCII al glifo A.

Le costanti numeriche intere possono essere espresse in formato decimale, ottale o esadecimale. In particolare, per le costanti ottali il numero inizia con 0 ed è seguito da cifre tra 0 e 7, per le esadecimali invece inzia con 0x o 0X e continua con valori numerici tra 0 e 9 o lettere minuscole o maiuscole tra A ed F.

Opzionalmente è possibile aggiungere un suffisso, per specificare il tipo della costante intera, tra cui:
  • U per unsigned
  • L per long
  • LL per long long
Sono ammesse anche le varianti in minuscolo. Qualche esempio:

int           a1 = 5;       /*    5 */
int           a2 = 5L;      /*    5 */
int           a3 = 0777U;   /*  511 */
int           a4 = 0XABCLL; /* 2748 */
long int      a5 = 123UL;   /*  123 */
long long int a6 = 0XFFULL; /*  255 */


Lo 0XABCLL è un numero esadecimale 0X, in particolare il numero è ABC e LL ci dice che è codificato come long long int. Similmente l'ultimo 0XFFULL ci dice che è una costante numerica intera esadecimale 0X di valore FF e di tipo ULL ossia unsigned long long int. 0777 è un valore ottale.

Per ottenere un valore negativo basta anteporre al numero l'operatore unario -. Ovviamente una istruzione come la seguente genera un errore:

int h = -0xFFU;

Qual è l'errore? si cerca di applicare l'operatore unario - ad una costante numerica dichiarata unsigned, quindi positiva. Anche scrivendo -255U si sarebbe ottenuto l'errore.

L'ultima costante rimasta è quella in virgola mobile. Come per gli interi è possibile ottenere la forma negativa facendo precedere la costante dall'operatore unario -. Le costanti intere in virgola mobile sono costituite da una sequenza di cifre seguite dal . o un . seguito dalla parte frazionaria o da entrambe le parti separate da un . cui si aggiunge e o E per la parte esponenziale che può avere segno - o no ed è costituita da una sequenza di cifre per la mantissa.

Tutte le costanti in virgola mobile sono di tipo double, a meno che non sia specificato un suffisso opzionale:
  • F per float
  • L per long double
Sono ammesse le varianti minuscole. Alcuni esempi:

    double f1 = 1.;            /*   1.0     */
    double f2 = .1;            /*   0.1     */
    double f3 = 1.1;           /*   1.1     */
    double f4 = 1.E-2;         /*   0.01    */
    double f5 = .1E3;          /* 100.0     */
    float  f6 = .1E-5F;        /*   1.E-6   */
    long double f7 = .1E-200L; /*   1.e-201 */


Se si tenta di assegnare una costante numerica double a un variabile float, il compilatore non segnala nulla. Anzi, con l'istruzione

float f = 1.7976931348623158e+308;

dove la costante numerica in virgola mobile double non è altro che DBL_MAX del file float.h, ossia il massimo valore memorizzabile da un double, la printf visualizza inf, che sta per infinito. Abbiamo quindi ecceduto la capacità di memoria del tipo float, ma non c'è errore nonostante si abbia sostanzialmente perso l'informazione.

Nota finale. Perchè non scrivere:

double  f1 = 1; 
/* al posto di */
double f2 = 1.;

L'istruzione è legittima e lavora come ci si aspetterebbe, ma con il primo caso la costante è trattata come intero e convertita implicitamente in double dal compilatore per l'assegnazione a f1. Nel secondo caso la costante nasce double e non ha bisogno di conversione o comunque è soggetta a una conversione esplicita.

Abbiamo quindi appreso
  • come scrivere costanti numeriche intere, in virgola mobile e carattere