Guida Corso programmazione linguaggio C - Lezione #4 : Data types,variabili e typedef (PT.2)

giovy2707

Utente Electrum
27 Giugno 2019
96
38
62
103
1665676775995.png


6.1 - Boolean literal


Per "boolean type literal" ci riferiamo ai valori letterali che possiamo utilizzare per rappresentare i nostri dati di tipo boolean, per rappresentare un dato di tipo boolean si usa la seguente notazione:

C:
_Bool variabile = 1; // CHE EQUIVALE A "vero"

//oppure

_Bool variabile = 0; //CHE EQUIVALE A "falso"

1665676844276.png



7 - Conversioni implicite


Per conversioni implicite si intende l'operazione di conversione che avviene in maniera automatica (la fa il compilatore) quando viene assegnato un determinato tipo di dato ad una variabile di tipo diverso.

1665676876799.png


Quando assegniamo in qualsiasi modo un valore ad una variabile possono verificarsi tre casi:
  • No Conversion

  • Type Promotion (promozione o "promozione di tipo")

  • Type Demotion (retrocessione o "retrocessione di tipo")

  • No conversion:
    • dato e variabile sono dello stesso tipo e quindi non avviene nessuna conversione.
1665676915016.png


C:
int a = 10;
int b = a: //sono dello stesso tipo, quindi nessun problema.

  • Type Promotion:
    1. dato e variabile non sono dello stesso tipo

    2. e la variabile di destinazione ha un data type più capiente di quello del dato quindi si ha una "promozione"

    3. Quello che accade è che il dato verrà convertito nel nuovo tipo e avrà anche più spazio a disposizione di quello che aveva nella variabile da cui proviene.

1665676975552.png


C:
int a = 10; // il numero 10 verrà copiato in una memoria più capiente
double b = a; // il 10 cambierà tipo da int a float quindi diventerà 10.0

  • Type Demotion:
    • dato e variabile non sono dello stesso tipo
    • e la variabile di destinazione ha un data type meno capiente di quello del dato quindi si ha una retrocessione

    • ovviamente ciò può causare problemi, infatti si può avere una perdita di informazione.

1665677071606.png


C:
double a = 10;
int b = a;


8 - Typedef


Il linguaggio C ci permette di "creare dei nuovi data-type sfruttando quelli esistenti" in verità quello che facciamo è dare quello che potremmo definire un "soprannome" ai data-type già esistenti che possiamo però usare come se fossero dei veri data-type. La sintassi per usare il typedef è la seguente:

C:
typedef type_id nuovo_nome;

Ad esempio possiamo dire che vogliamo usare la parola "ciao" per indicare il tipo int, per farlo dobbiamo prima dire al compilatore, che vogliamo usare questo nuovo "alias" per riferirci al tipo int:

C:
typedef int CIAO;

Se ora vogliamo a dichiarare una variabile di tipo int usando il nuovo alias ci basta fare così:

C:
CIAO variabile;

la variabile appena creata sarà una variabile di tipo int.

1665677225059.png
 

Allegati

  • 1665676975588.png
    1665676975588.png
    12.7 KB · Visualizzazioni: 2
  • 4.Data types e variabili.pdf
    1.7 MB · Visualizzazioni: 3
Per "boolean type literal" ci riferiamo ai valori letterali che possiamo utilizzare per rappresentare i nostri dati di tipo boolean, per rappresentare un dato di tipo boolean si usa la seguente notazione:

C:
_Bool variabile = 1; // CHE EQUIVALE A "vero"

//oppure

_Bool variabile = 0; //CHE EQUIVALE A "falso"
I bool solitamente si usano in questo modo:
C:
#include <stdbool.h>
bool flag = true; // oppure false
Sono stati introdotti con lo standard C99 dove non avevano modo di introdurre le keyword bool, true e false perché un linguaggio come il C la retrocompatibilità è importantissima e aggiungendo quelle keyword del codice prima funzionante avrebbe poi portato ad errori di compilazione. Hanno usato _Bool (e anche _Complex, _Atomic, etc.) perché lo standard dice che tutti i nomi che iniziano per un underscore seguito da una lettera maiuscola sono riservati per questi sviluppi futuri. Tuttavia, le keyword che iniziano per underscore + maiuscola non sono pensate per essere usate direttamente, ma è più opportuno usarle implicitamente dopo aver incluso l'header che vi fa da interfaccia: per i booleani si fa #include <stdbool.h> e si usa roba tipo bool flag = false;, per i complessi si fa #include <complex.h> e si usa double complex z1 = 1.0 + 2.0 * I;, e così via.

Quando assegniamo in qualsiasi modo un valore ad una variabile possono verificarsi tre casi:
  • No Conversion
  • Type Promotion (promozione o "promozione di tipo")
  • Type Demotion (retrocessione o "retrocessione di tipo")
Permettimi di fare un esempio più approfondito visto che è un problema subdolo che anche a me capita di fare spesso:
C:
// nota: il massimo valore di int è: (1 << 31) - 1 = 2147483647
long x = 64129542144;
long y = 1 << 40;
int z = x;
Nella prima riga non avviene nessuna conversione e tutto funziona come ci si aspetta perché 64129542144 è fuori range per un int e viene interpretato come un long. Nella seconda riga abbiamo 1 << 40, che anche lui è fuori range per un int; tuttavia, i due letterali presi singolarmente (1 e 40) sono molto piccoli e sono chiaramente degli int. Il calcolo 1 << 40, che in realtà avviene a tempo di compilazione, butta fuori un int (perché i due letterali sono int) che poi viene promosso a long. Nella seconda riga ci aspettiamo che la variabile y valga tantissimo (1099511627776), ma in realtà vale 0. Nella terza riga avviene chiaramente type demotion e il valore di z è -294967296 che sarebbero i 32 bit più bassi di 64129542144 (111011101110011010110010100000000000) espressi come numero intero in complemento a due.

L'errore che c'è sulla seconda riga, in particolare, mi capita frequentemente: scrivi 1 << x e ti accorgi dopo che in realtà volevi scrivere 1ULL << x (1 visto come unsigned long long).

Valuta tu se vale la pena correggere il tuo post (anche se quelli che ti ho segnalato non sono errori) o se preferisci lasciarlo così com'è per evitare di fare spiegazioni eccessivamente dettagliate in una guida dove vuoi spiegare le basi. Io ho scritto questo post con l'intenzione di aggiungere valore al thread più che per correggere quello che hai scritto tu ;)
 
  • Mi piace
  • Incredibile
Reazioni: 0xbro e giovy2707
I bool solitamente si usano in questo modo:
C:
#include <stdbool.h>
bool flag = true; // oppure false
Sono stati introdotti con lo standard C99 dove non avevano modo di introdurre le keyword bool, true e false perché un linguaggio come il C la retrocompatibilità è importantissima e aggiungendo quelle keyword del codice prima funzionante avrebbe poi portato ad errori di compilazione. Hanno usato _Bool (e anche _Complex, _Atomic, etc.) perché lo standard dice che tutti i nomi che iniziano per un underscore seguito da una lettera maiuscola sono riservati per questi sviluppi futuri. Tuttavia, le keyword che iniziano per underscore + maiuscola non sono pensate per essere usate direttamente, ma è più opportuno usarle implicitamente dopo aver incluso l'header che vi fa da interfaccia: per i booleani si fa #include <stdbool.h> e si usa roba tipo bool flag = false;, per i complessi si fa #include <complex.h> e si usa double complex z1 = 1.0 + 2.0 * I;, e così via.


Permettimi di fare un esempio più approfondito visto che è un problema subdolo che anche a me capita di fare spesso:
C:
// nota: il massimo valore di int è: (1 << 31) - 1 = 2147483647
long x = 64129542144;
long y = 1 << 40;
int z = x;
Nella prima riga non avviene nessuna conversione e tutto funziona come ci si aspetta perché 64129542144 è fuori range per un int e viene interpretato come un long. Nella seconda riga abbiamo 1 << 40, che anche lui è fuori range per un int; tuttavia, i due letterali presi singolarmente (1 e 40) sono molto piccoli e sono chiaramente degli int. Il calcolo 1 << 40, che in realtà avviene a tempo di compilazione, butta fuori un int (perché i due letterali sono int) che poi viene promosso a long. Nella seconda riga ci aspettiamo che la variabile y valga tantissimo (1099511627776), ma in realtà vale 0. Nella terza riga avviene chiaramente type demotion e il valore di z è -294967296 che sarebbero i 32 bit più bassi di 64129542144 (111011101110011010110010100000000000) espressi come numero intero in complemento a due.

L'errore che c'è sulla seconda riga, in particolare, mi capita frequentemente: scrivi 1 << x e ti accorgi dopo che in realtà volevi scrivere 1ULL << x (1 visto come unsigned long long).

Valuta tu se vale la pena correggere il tuo post (anche se quelli che ti ho segnalato non sono errori) o se preferisci lasciarlo così com'è per evitare di fare spiegazioni eccessivamente dettagliate in una guida dove vuoi spiegare le basi. Io ho scritto questo post con l'intenzione di aggiungere valore al thread più che per correggere quello che hai scritto tu

I bool solitamente si usano in questo modo:
C:
#include <stdbool.h>
bool flag = true; // oppure false
Sono stati introdotti con lo standard C99 dove non avevano modo di introdurre le keyword bool, true e false perché un linguaggio come il C la retrocompatibilità è importantissima e aggiungendo quelle keyword del codice prima funzionante avrebbe poi portato ad errori di compilazione. Hanno usato _Bool (e anche _Complex, _Atomic, etc.) perché lo standard dice che tutti i nomi che iniziano per un underscore seguito da una lettera maiuscola sono riservati per questi sviluppi futuri. Tuttavia, le keyword che iniziano per underscore + maiuscola non sono pensate per essere usate direttamente, ma è più opportuno usarle implicitamente dopo aver incluso l'header che vi fa da interfaccia: per i booleani si fa #include <stdbool.h> e si usa roba tipo bool flag = false;, per i complessi si fa #include <complex.h> e si usa double complex z1 = 1.0 + 2.0 * I;, e così via.


Permettimi di fare un esempio più approfondito visto che è un problema subdolo che anche a me capita di fare spesso:
C:
// nota: il massimo valore di int è: (1 << 31) - 1 = 2147483647
long x = 64129542144;
long y = 1 << 40;
int z = x;
Nella prima riga non avviene nessuna conversione e tutto funziona come ci si aspetta perché 64129542144 è fuori range per un int e viene interpretato come un long. Nella seconda riga abbiamo 1 << 40, che anche lui è fuori range per un int; tuttavia, i due letterali presi singolarmente (1 e 40) sono molto piccoli e sono chiaramente degli int. Il calcolo 1 << 40, che in realtà avviene a tempo di compilazione, butta fuori un int (perché i due letterali sono int) che poi viene promosso a long. Nella seconda riga ci aspettiamo che la variabile y valga tantissimo (1099511627776), ma in realtà vale 0. Nella terza riga avviene chiaramente type demotion e il valore di z è -294967296 che sarebbero i 32 bit più bassi di 64129542144 (111011101110011010110010100000000000) espressi come numero intero in complemento a due.

L'errore che c'è sulla seconda riga, in particolare, mi capita frequentemente: scrivi 1 << x e ti accorgi dopo che in realtà volevi scrivere 1ULL << x (1 visto come unsigned long long).

Valuta tu se vale la pena correggere il tuo post (anche se quelli che ti ho segnalato non sono errori) o se preferisci lasciarlo così com'è per evitare di fare spiegazioni eccessivamente dettagliate in una guida dove vuoi spiegare le basi. Io ho scritto questo post con l'intenzione di aggiungere valore al thread più che per correggere quello che hai scritto tu ;)
Grazie per le preziose informazioni 😉, sono informazioni molto interessanti, penso le implementerò nella guida il prima possibile, anche se sono molto dettagliate penso diano una visione ancora più chiara sul linguaggio, cosa sicuramente molto utile per chi cerca di imparare un linguaggio ostico come il C.