TIPI DI DATO IN C - PARTE 1°

In un qualsiasi linguaggio di programmazione le informazioni per essere manipolate necessitano di zone di memoria dove possono essere temporaneamente salvate. Le variabili sono il meccanismo che consente di ottenere questo obbiettivo. Le variabili sono caratterizzate dal tipo che definisce il range (intervallo) di valori ammessi e il set (insieme) di operazioni possibili. In C i tipi di dato elementari disponibili sono:

Tipi testuali

nome tipo dichiarazione dimensione
char char ch 1 byte
char [N] char stringa[10] 1 byte per il numero di elementi dell'array

Tipi Numerici Interi

nome tipo dichiarazione dimensione
bool bool x 1 byte
short short sx 2 byte
long / int int x
long y
4 byte

Tipi Numerici con Decimali

nome tipo dichiarazione dimensione
float float a 4 byte
double double d 8 byte

Tipi Numerici Complessi

nome tipo dichiarazione dimensione
float _Complex float _Complex a 8 byte
double _Complex double _Complex d 16 byte

In realtà, a seconda del compilatore C utilizzato la varietà dei tipi disponibili si amplia notevolmente. Ad esempio in DEV C++ i tipi elementari presenti sono molti di più come si vede nel seguente sorgente in C.

#include <stdio.h>
int main(int argc, char *argv[])
{
    printf("###################################################\n");
    printf("#  T I P I    D I   D A T O   I N   D E V  C + +  #\n");
    printf("###################################################\n\n");
    printf("- Tipi Testuali: ----------------------------------\n");
    printf("    char:                 %2d byte;\n",sizeof(char));
    printf("    char [10]:            %2d byte;\n",sizeof(char[10]));
    printf("---------------------------------------------------\n\n");

    printf("- Tipi Numerici Interi: ---------------------------\n");
    printf("    bool:                 %2d byte;\n",sizeof(bool));
    printf("    short:                %2d byte \n",sizeof(short));
    printf("      unsigned short:     %2d byte \n",sizeof(unsigned short));
    printf("      signed short:       %2d byte;\n",sizeof(signed short));
    printf("    int:                  %2d byte \n",sizeof(int));
    printf("      unsigned int:       %2d byte \n",sizeof(unsigned int));
    printf("      signed int:         %2d byte \n",sizeof(signed int));
    printf("      short int:          %2d byte \n",sizeof(short int));
    printf("      long int:           %2d byte \n",sizeof(long int));
    printf("      unsigned short int: %2d byte \n",sizeof(unsigned short int));
    printf("      signed short int:   %2d byte \n",sizeof(signed short int));
    printf("      unsigned long int:  %2d byte \n",sizeof(unsigned long int));
    printf("      signed long int:    %2d byte \n",sizeof(signed long int));
    printf("      long long int:      %2d byte;\n",sizeof(long long int));
    printf("    long:                 %2d byte \n",sizeof(long));
    printf("      unsigned long:      %2d byte \n",sizeof(unsigned long));
    printf("      signed long:        %2d byte \n",sizeof(unsigned long));
    printf("      long long:          %2d byte \n",sizeof(long long));
    printf("      unsigned long long: %2d byte \n",sizeof(unsigned long long));
    printf("      signed long long:   %2d byte;\n",sizeof(signed long long));
    printf("---------------------------------------------------\n\n");

    printf("- Tipi Numerici Decimali: --------------------------\n");
    printf("    float:                %2d byte;\n",sizeof(float));
    printf("    double:               %2d byte;\n",sizeof(double));
    printf("    long double:          %2d byte;\n",sizeof(long double));
    printf("---------------------------------------------------\n\n");

    printf("- Tipi Numerici Complessi : -----------------------\n");
    printf("    float _Complex:       %2d byte;\n",sizeof(float _Complex));
    printf("    double _Complex:      %2d byte;\n",sizeof(double _Complex));
    printf("    long double _Complex: %2d byte;\n",sizeof(long double _Complex));
    printf("---------------------------------------------------\n\n");
}

La sua esecuzione produce questo output:

NOTE:
 - La funzione C sizeof(Tipo) consente di sapere la dimensione in byte di ogni
Tipo di variabile.
 - La funzione
 printf(Frase) consente di stampare a video l'argomento "Frase"

L'occupazione in byte di un tipo non è universale ma dipende dalle diverse architetture hardware utilizzate e dalle numerose varianti di (compilatori) C esistenti. Ad esempio il tipo Int occupa 32 bit con alcuni compilatori  (esempio Dev C++) mentre in altri Int usa solo 16 bit (Ansi C).
NOTA: Il compilatore è quel programma che trasforma il sorgente testuale (contenente le istruzioni in un determinato linguaggio) in eseguibile (contenente istruzioni in assembler o codice macchina).

Table A: dimensione in bit dei tipi interi per alcuni sistemi

Tipo

Macintosh

Linux su PC

IBM PC
Windows XP
and Windows NT

ANSI C Minimum

char

8

8

8

8

int

32

32

32

16

short

16

16

16

16

long

32

32

32

32

long long

64

64

64

64

Tabella B:  alcune informazioni relative ai valori Floating-point supportati da alcuni sistemi

Tipo

Macintosh

Linux su PC

IBM PC
Windows XP
and Windows NT

ANSI C Minimum

float

6 digits

6 digits

6 digits

6 digits

 

–37 to 38

–37 to 38

–37 to 38

–37 to 37

double

18 digits

15 digits

15 digits

10 digits

 

–4931 to 4932

–307 to 308

–307 to 308

–37 to 37

long double

18 digits

18 digits

18 digits

10 digits

 

–4931 to 4932

–4931 to 4932

–4931 to 4932

–37 to 37

Per ogni tipo nella prima riga sono indicati il numero di digit significativi.
Nella seconda riga l'intervallo (inteso come esponente di base 10) dei valori ammessi
 
LABORATORIO: (clicca qui per scaricare i files necessari)

L'esercitazione vuole evidenziare le modalità di registrazione, all'interno di un un file DOS/WIN, dei diversi tipi di dato elementare indicati all'inizio di questa pagina web.

L'eseguibile CreaFile.exe, appena scaricato, ci consente di generare 9 file. Il codice sorgente in C di CreaFile.exe è il seguente

#include <stdio.h>
#define _Complex_I  (0.0F +  1.0iF)

int main(int argc, char *argv[])
{
    int n;
    FILE *fpo;

    // #################################################
    // Definizione dei dati	
    // #################################################
    // Caratteri ---------------------------------------
    char ch='A';             // 1 Byte
    char stringa[]="ABCD";   // 4 Byte
    // Numerici interi ---------------------------------
    bool vero=true, falso=false;
    short sx=16961;    // 65+66*256
    int ix=1329678659; // 67+73*256+65*256^2+79*256^3
    long long lx=0;
    // Numerici razionali -------------------------------
    float f=3242803968.0002;
    double lf=61084138414899658000000000000000000000000000000000000000000000000000000000.0;
    // Numerici Complessi -------------------------------
    float _Complex f_i=f+f*_Complex_I;
    double _Complex d_i=lf+lf*_Complex_I;

    // #################################################
    // File di testo con 4 caratteri: AB
    // #################################################
    fpo=fopen(".\\File_T_char.dat","w+");
    ch='A';  // in ascii 65
    putc(ch,fpo);
    ch=ch+1;  // dovrebbe essere 66 => B
    putc(ch,fpo);
    ch=ch+1;  // dovrebbe essere 67 => C
    putc(ch,fpo);
    ch=ch+1;  // dovrebbe essere 68 => D
    putc(ch,fpo);
    fclose(fpo);

    // #################################################
    // File testuale con Array di 4 caratteri: CIAO
    // #################################################
    fpo=fopen(".\\File_T_string.dat","w+");
    fprintf(fpo,"%s",stringa);
    fclose(fpo);
    
    // #################################################
    // File binario contenente 4 boolean
    // #################################################
    fpo=fopen(".\\File_NI_bool.dat","wb+");
    n=fwrite(&vero,sizeof(vero),1,fpo);
    n=fwrite(&falso,sizeof(falso),1,fpo);
    n=fwrite(&falso,sizeof(falso),1,fpo);
    n=fwrite(&vero,sizeof(vero),1,fpo);
    fclose(fpo);

    // #################################################
    // File binario contenente 2 short
    // #################################################
    fpo=fopen(".\\File_NI_short.dat","wb+");
    n=fwrite(&sx,sizeof(sx),1,fpo);
    sx=sx+1;
    n=fwrite(&sx,sizeof(sx),1,fpo);
    fclose(fpo);

    // #################################################
    // File binario contenente 2 int
    // #################################################
    fpo=fopen(".\\File_NI_int.dat","wb+");
    n=fwrite(&ix,sizeof(ix),1,fpo);
    ix=ix+1;
    n=fwrite(&ix,sizeof(ix),1,fpo);
    fclose(fpo);

    // #################################################
    // File binario contenente un float
    // #################################################
    fpo=fopen(".\\File_NR_float.dat","wb+");
    n=fwrite(&f,sizeof(f),1,fpo);
    fclose(fpo);

    // #################################################
    // File binario contenente un double
    // #################################################
    fpo=fopen(".\\File_NR_double.dat","wb+");
    n=fwrite(&lf,sizeof(lf),1,fpo);
    fclose(fpo);

    // #################################################
    // File binario contenente un numero complesso float
    // #################################################
    fpo=fopen(".\\File_NR_floatcomplex.dat","wb+");
    n=fwrite(&f_i,sizeof(f_i),1,fpo);
    fclose(fpo);

    // #################################################
    // File binario contenente un numero complesso double
    // #################################################
    fpo=fopen(".\\File_NR_doublecomplex.dat","wb+");
    n=fwrite(&d_i,sizeof(d_i),1,fpo);
    fclose(fpo);
    
    printf("Files generati!");
}

NOTE:
 - La funzione C fopen(NomeFile,modo) consente di creare/aprire un file
 - La funzione C fwrite consente di scrivere all'interno di un file
 

L'esecuzione del programma produce i seguenti files (si notino le dimensioni!) [videata dos]:

lo stesso elenco in windows viene così presentato (si notino le dimensioni!):

I files prodotti contenengono dati di tipo omogeneo ed esattamente:

Nome File Contenuto Codice in C per la creazione del file
File_T_char.dat
dimensione = 4 byte
4 caratteri ascii:  'A' 'B' 'C' e 'D'
fpo=fopen(".\\File_T_char.dat","w+");
char ch='A';  // in ascii 65
putc(ch,fpo);
ch=ch+1;  // dovrebbe essere 66 => B
putc(ch,fpo);
ch=ch+1;  // dovrebbe essere 67 => C
putc(ch,fpo);
ch=ch+1;  // dovrebbe essere 68 => D
putc(ch,fpo);
fclose(fpo);
File_T_string.dat
dimensione = 4 byte
la stringa (array) "ABCD"
fpo=fopen(".\\File_T_string.dat","w+");
fprintf(fpo,"%s","ABCD");
fclose(fpo);
File_NI_bool.dat
dimensione = 4 byte
contiene 4 valori booleani: true, false, false e true
bool vero=true, falso=false;
fpo=fopen(".\\File_NI_bool.dat","wb+");
n=fwrite(&vero,sizeof(vero),1,fpo);
n=fwrite(&falso,sizeof(falso),1,fpo);
n=fwrite(&falso,sizeof(falso),1,fpo);
n=fwrite(&vero,sizeof(vero),1,fpo);
fclose(fpo);
File_NI_short.dat
dimensione = 4 byte
due numeri short: il numero intero  x = 16.961 =65+66 x 256 e il numero y = x+1 = 16.962 =66+66 x 256
short sx=16961;
fpo=fopen(".\\File_NI_short.dat","wb+");
n=fwrite(&sx,sizeof(sx),1,fpo);
sx=sx+1;
n=fwrite(&sx,sizeof(sx),1,fpo);
fclose(fpo);
File_NI_int.dat
dimensione = 8 byte
 
due numeri interi: il numero intero X= 1.329.678.659 = 67 x 2560+73 x 2561+65 x 2562+79 x 2563 e il numero Y = X+1 = 1.329.678.660 = 68 x 2560+73 x 2561+65 x 2562+79 x 2563
int ix=1329678659;
fpo=fopen(".\\File_NI_int.dat","wb+");
n=fwrite(&ix,sizeof(ix),1,fpo);
ix=ix+1;
n=fwrite(&ix,sizeof(ix),1,fpo);
fclose(fpo);
File_NR_float.dat
dimensione = 4 byte
il numero decimale 3.242.803.968,0002
float f=3242803968.0002;
fpo=fopen(".\\File_NR_float.dat","wb+");
n=fwrite(&f,sizeof(f),1,fpo);
fclose(fpo);
File_NR_double.dat
dimensione = 8 byte
il numero decimale y=
61084138414899658000000000000000000000000000
000000000000000000000000000000,0002
;
double lf=61084138414899658000000......;
fpo=fopen(".\\File_NR_double.dat","wb+");
n=fwrite(&lf,sizeof(lf),1,fpo);
fclose(fpo);
File_NR_floatcomplex.dat
dimensione = 8 byte
il numero complesso 3.242.803.968,0002+3.242.803.968,0002*I

dove I è un valore t.c. I2=-1

#define _Complex_I  (0.0F +  1.0iF)
float _Complex f_i=f+f*_Complex_I;
fpo=fopen(".\\File_NR_floatcomplex.dat","wb+");
n=fwrite(&f_i,sizeof(f_i),1,fpo);
fclose(fpo);
File_NR_doublecomplex.dat
dimensione = 16 byte
il numero complesso y+y*I dove y è lo stesso numero decimale usato per i double.
#define _Complex_I  (0.0F +  1.0iF)
double _Complex d_i=lf+lf*_Complex_I;
fpo=fopen(".\\File_NR_doublecomplex.dat","wb+");
n=fwrite(&d_i,sizeof(d_i),1,fpo);
fclose(fpo);

L'eseguibile VisualizzaFile.exe consente di analizzare i contenuti dei singoli files appena prodotti. Il programma visualizza i contenuti dei files interpretandoli come se fossero composti da sequenze di:
- byte (unsigned char) e li visualizza in:
    a) esadecimale [HEX dump]
    b) decimale [DECIMAL dump]
    c) sequenza di caratteri [ASCII dump]
- numeri interi short composti da coppie di byte [SHORT dump]
- numeri interi int
 composti da coppie di byte [INT dump]
- numeri con virgola mobile float composti da 4 byte in rappresentazione IEEE754 a 32 bit
[FLOAT dump]

Il sorgente in C di VisualizzaFile.exe è il seguente:

#include <stdio.h>
#include <stdlib.h>
int s;
static int r;
void Invio(int p, int q)
{
     r++;
     if (p<=0) return;
     if ( ( (r % q)==0) && (r!=0) )
          printf("\n                ");
}
void DumpFile(char *Nf)
{
    unsigned char d;
    short sx;
    int x;
    int r=0;
    float f;
    int n=0;
    FILE *fpo;
    printf("################################################\n");
    printf("# File: %s\n",Nf);
    printf("################################################\n");
    fpo=fopen(Nf,"rb");

    // Lettura in Esadecimale
    rewind(fpo);
    printf("- HEX dump     :");
    r=0;
    n = fread(&d, sizeof(char), 1, fpo);
    while (!feof(fpo))
    {
	 printf("[%02X] ",d);
         n = fread(&d, sizeof(char), 1, fpo);
         Invio(n,4);
    }
    printf("\n------------------------------------------------\n");

    // Lettura in Decimale
    rewind(fpo);
    r=0;
    printf("- DECIMALE dump:");
    n = fread(&d, sizeof(char), 1, fpo);
    while (!feof(fpo))
    {
	 printf("[%3d] ",d);
         n = fread(&d, sizeof(char), 1, fpo);
         Invio(n,4);
    }
    printf("\n------------------------------------------------\n");

    if (s>10)
    {
        // Lettura in unsigned 
        rewind(fpo);
        r=0;
        printf("- SIGN.DEC dump:");
        n = fread(&d, sizeof(char), 1, fpo);
        while (!feof(fpo))
        {
    	     printf("[%3d] ",(signed char)d);
             n = fread(&d, sizeof(char), 1, fpo);
             Invio(n,4);
        }
        printf("\n------------------------------------------------\n");
    }
    
    // Lettura in Ascii
    rewind(fpo);
    r=0;
    printf("- ASCII dump   :");
    n = fread(&d, sizeof(char), 1, fpo);
    while (!feof(fpo))
    {
	 printf("[%c] ",d);
         n = fread(&d, sizeof(char), 1, fpo);
         Invio(n,4);
    }
    printf("\n------------------------------------------------\n");

    // Lettura in SHORT
    rewind(fpo);
    r=0;
    printf("- SHORT dump   :");
    n = fread(&sx,  sizeof(short), 1, fpo);
    while (n>0)
    {
	 printf("[%hd] ",sx);
         n = fread(&sx, sizeof(short), 1, fpo);
         Invio(n,4);
    }
    printf("\n------------------------------------------------\n");	

    // Lettura in INT
    rewind(fpo);
    printf("- INT dump     :");
    r=0;
    n = fread(&x, sizeof(int), 1, fpo);
    while (n>0)
    {
	 printf("[%d] ",x);
         n = fread(&x, sizeof(int), 1, fpo);
         Invio(n,2);
    }
    printf("\n------------------------------------------------\n");	

    if (s<10)
    {
        // Lettura in FLOAT
        rewind(fpo);
        r=0;
        printf("- FLOAT dump   :");
        n = fread(&f, sizeof(int), 1, fpo);
        while (n>0)
        {
    	     printf("[%lf] ",f);
             n = fread(&f, sizeof(int), 1, fpo);
             Invio(n,1);
        }
        printf("\n------------------------------------------------\n");	
    }
    fclose(fpo);
}
void AsciiTable()
{
   int i,r=2;
   printf("-----------------------------------\n");
   printf("|    T A B E L L A    A S C I I   |\n");
   printf("--+--------------------------------\n  |");
   for (i=0 ; i<16 ; printf(" %X",i++) );
   printf("\n--+--------------------------------\n");
   for (r=2 ; r < 16 ; r++)
   {
       printf(" %X|",r);
       for (i=0; i<16 ; i++)
           printf(" %c",r*16+i);
       printf("\n");
   }
   printf("--+--------------------------------\n  |");
   for (i=0 ; i<16 ; printf(" %X",i++) );
   printf("\n--+--------------------------------\n");
}

int main(int argc, char *argv[])
{
   s=atoi(argv[1]);
   if (s==1)
      DumpFile(".\\File_T_char.dat");
   else if (s==2)
      DumpFile(".\\File_T_string.dat");
   else if (s==3)
      DumpFile(".\\File_NI_bool.dat");
   else if (s==4)
      DumpFile(".\\File_NI_short.dat");
   else if (s==5)
      DumpFile(".\\File_NI_int.dat");
   else if (s==6)
      DumpFile(".\\File_NR_float.dat");
   else if (s==7)                                                       
      DumpFile(".\\File_NR_double.dat");
   else if (s==8)
      DumpFile(".\\File_NR_floatcomplex.dat");
   else if (s==9)                                                       
      DumpFile(".\\File_NR_doublecomplex.dat");
   else if (s==14)
      DumpFile(".\\File_NI_NegShort.dat");
   else if (s==15)
      DumpFile(".\\File_NI_NegInt.dat");
   else if (s==99)
      AsciiTable();
   else
   {
      printf("Sintassi: VisualizzaFile \n\ndove:\n");
      printf("1 => File_T_char.dat\n");
      printf("2 => File_T_string.dat\n");
      printf("----------------------------\n");
      printf("3 => File_NI_bool.dat\n");
      printf("4 => File_NI_short.dat\n");
      printf("5 => File_NI_int.dat\n");
      printf("----------------------------\n");
      printf("6 => File_NR_float.dat\n");
      printf("7 => File_NR_double.dat\n");
      printf("8 => File_NR_floatcomplex.dat\n");
      printf("9 => File_NR_doublecomplex.dat\n");
      printf("----------------------------\n");
      printf("14 => File_NI_NegShort.dat\n");
      printf("15 => File_NI_NegInt.dat\n");
      printf("----------------------------\n");
      printf("99 => ASCII Dump\n");
   }
}

NOTE:
 - La funzione C fread(Variabile,nByte,.,idFile) carica in
Variabile un numero di byte nByte letti dal file idFile.
 

Analizziamo ora l'output prodotto da VisualizzaFile.exe per ogni singolo file

File_T_char.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_T_char.dat
################################################
- HEX dump     :[41] [42] [43] [44]
------------------------------------------------
- DECIMALE dump:[ 65] [ 66] [ 67] [ 68]
------------------------------------------------
-
ASCII dump   :[A] [B] [C] [D]
------------------------------------------------
- SHORT dump   :[16961] [17475]
------------------------------------------------
- INT dump     :[1145258561]
------------------------------------------------
- FLOAT dump   :[781.035217]
------------------------------------------------
In giallo è evidenziata l'interpretazione valida del file (contiene infatti la parola "ABCD").
Per interpretazione valida si intende che la scelta del tipo utilizzato durante la lettura è compatibile con quello utilizzato nella scrittura del dato. L'interpretazione valida consente di visualizzare correttamente il valore reale del dato registrato nel file. Ad esempio se per errore interpretassi il file "File_T_Char.dat" come sequenza di numeri int la lettura mi restituirebbe 11.452.558.561 che non corrisponde al valore reale che è stato salvato in origine: "ABCD".

Le visualizzazioni in HEX e DECIMALE sono di tipo sistemistico e servono per analizzare i dati registrati qualora non si conosca il tipo originale usato durante il salvataggio dei file. Nella rappresentazione HEX la coppia di lettere può essere vista come la notazione in base 256.

Nella lettura come SHORT (ovvero uso una variabile short) i 4 byte del file vengono letti a due a due. In hex quindi ho [41][42] e [43][44]. In decimale ho [65][66] che corrisponde: 65+66*256= 16.961 mentre [67][68] corrisponde a: 67+68*256= 17.475. Si noti come la sequenza dei coefficienti nella registrazione in DOS/WIN, contrariamente alla notazione in base 256 vista in classe, risulta essere ribaltata. In altre parole se il calcolatore registrasse in notazione decimale (e non binaria) il numero (1239)10 verrebbe salvato come (9321)10

Nella lettura come INT
(ovvero uso una variabile int) i 4 byte del file vengono letti in un unico colpo. In hex quindi leggo [41][42][43][44] e in decimale [65][66][67][68]. Utilizzando questi valori come coefficienti della serie di potenze con base 256 avrò: 65+66 x 256+67 x 2562+68 x 2563 = 1.145.258.561 che è il valore nell'INT dump. Si noti come ancora la sequenza dei coefficienti risulti ancora ribaltata (il decimale + a sinistra è usato per la potenza meno significativa).

Nella lettura come FLOAT
(ovvero uso una variabile float) i 4 byte del file vengono letti in un unico colpo ([41][42][43][44]) ed interpretati come se fossero una notazione floating point (FP). In realtà in dos/win la sequenza di bit relativa ad una rappresentazione numerica viene salvata su disco partendo dal byte più a destra. Ad esempio se la sequenza salvata è [41][42][43][44] la rappresentazione originale FP è quella che si ottiene ribaltando l'ordine dei byte ovvero: [44][43][42][41].
Quindi se a
[41][42][43][44] corrisponde la sequenza di 32 bit:
0
1000001010000100100001101000100 
la rappresentazione FP originale è
0 10001000 1000011
0 100001001000001

che corrisponde alla notazione normalizzata (1,10000100100001101000100)2 x 29. Utilizzando nella pagina che decodifica IEEE754 la sequenza ribaltata [44][43][42][41] otteniamo il decimale (781,0352172851562) che è quello visualizzato nel FLOAT dump.

 
File_T_string.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_T_string.dat
################################################
- HEX dump     :[41] [42] [43] [44]
------------------------------------------------
- DECIMALE dump:[ 65] [ 66] [ 67] [ 68]
------------------------------------------------
-
ASCII dump   :[A] [B] [C] [D]
------------------------------------------------
- SHORT dump   :[16961] [17475]
------------------------------------------------
- INT dump     :[1145258561]
------------------------------------------------
- FLOAT dump   :[781.035217]
------------------------------------------------
In giallo è evidenziata l'interpretazione valida del file (contiene infatti la parola "ABCD").
Questo esempio evidenzia come una parola (stringa) di N caratteri è equivalente alla sequenza dei singoli N caratteri (byte).

File_NI_bool.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_NI_bool.dat
################################################
- HEX dump :[01] [00] [00] [01]
------------------------------------------------
- DECIMALE dump:[ 1] [ 0] [ 0] [ 1]
------------------------------------------------
- ASCII dump :[☺] [ ] [ ] [☺]
------------------------------------------------
- SHORT dump :[1] [256]
------------------------------------------------
- INT dump :[16777217]
------------------------------------------------
- FLOAT dump :[0.000000]
------------------------------------------------
L'interpretazione valida del file richiede l'utilizzo del tipo corretto bool.
Si noti che al valore true (vero) corrisponde al numero decimale uno mentre al false (falso) lo zero. Nell'ASCII dump la faccina è il simbolo associato al carattere ascii 1 mentre il 2° byte non si vede poiché contiene il carattere nullo (in c '\0' - in ascii 0)

Nello SHORT dump (ovvero uso una variabile short) vedo il valore 1 e 256 infatti 1 x 2560+0 x 2561= 1 e 0 x 2560+1 x 2561 =256.

Nello INT dump  (ovvero uso una variabile int) vedo il numero 16.777.217. Infatti la variabile int utilizzata nella lettura carica 4 byte al colpo ovvero [1][0][0][1]. Sfruttando i criteri di rappresentazione in base 256 ottengo: 1 x 2560+0 x 2561 + 0 x 2562+1 x 2563 = 16.777.217

Nella lettura come FLOAT (ovvero uso una variabile float) i 4 byte del file vengono letti in un unico colpo. I 4 byte hex [01][00][00][01] vengono considerati come se fosse una notazione floating point. A questi 4 byte corrisponde quindi la seguente sequenza di 32 bit: 0 00000010 00000000000000000000001  che coincide con il decimale 1,0000001192092895 x 2-125 (che è 2,35 x 10-35 ~ 0). [Attenzione non ho ribaltato la sequenza di byte per ottenere la corretta rappresentazione FP semplicemente perché [01][00][00][01] è palindroma]

 
File_NI_short.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_NI_short.dat
################################################
- HEX dump :[41] [42] [42] [42]
------------------------------------------------
- DECIMALE dump:[ 65] [ 66] [ 66] [ 66]
------------------------------------------------
- ASCII dump :[A] [B] [B] [B]
------------------------------------------------
- SHORT dump :[16961] [16962]
------------------------------------------------
- INT dump :[1111638593]
------------------------------------------------
- FLOAT dump :[48.564701]
------------------------------------------------

In giallo è evidenziata l'interpretazione corretta del file (contiene infatti i numeri interi: 16.961 e 16.962).  Riprendendo le stesse modalità viste in precedenza vediamo che 16.961 corrisponde alla sequenza di byte in Ascii "AB" (65 + 66 x 256) mentre 16.962 a "BB" (66 + 66 x 256).

Se leggo il file con una variabile int
 (INT dump) tutti e i 4 byte [65][66][66][66] verranno letti assieme ed interpretati come i coefficienti della notazione in base 256: 65+66 x 256+66 x 2562+66 x 2563  = 1.111.638.593

Nella lettura come FLOAT (ovvero uso una variabile float) i 4 byte del file vengono letti in un unico colpo ([41][42][42][42]) ed interpretati come se fosse una notazione floating point (FP). Come si è detto in dos/win la sequenza di bit relativa a una rappresentazione numerica viene salvata su disco partendo dal byte più a destra. Quindi se la sequenza salvata è [41][42][42][42] la reale rappresentazione in FP è : [42][42][42][41].
Per cui se a
[41][42][42][42] corrisponde la sequenza di 32 bit:
0
1000001010000100100001001000010 
la rappresentazione FP originale è
0 10000100 1000010
0 100001001000010
che corrisponde alla notazione normalizzata (1,10000100100001001000001)2 x 25. Utilizzando nella pagina che decodifica IEEE754 la sequenza ribaltata [42][42][42][41] otteniamo il decimale (48,564701080322266) visualizzato nel FLOAT dump.


File_NI_int.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_NI_int.dat
################################################
- HEX dump      :[43] [49] [41] [4f]
                 [44] [49] [41] [4f]
------------------------------------------------
- DECIMALE dump :[ 67] [ 73] [ 65] [ 79]
                 [ 68] [ 73] [ 65] [ 79]
------------------------------------------------
- ASCII dump    :[C] [I] [A] [O]
                 [D] [I] [A] [O]
------------------------------------------------
- SHORT dump    :[18755] [20289]
                 [18756] [20289]
------------------------------------------------
- INT dump      :[1329678659]
                 [1329678660]

------------------------------------------------
- FLOAT dump    :[3242803968.000000]
                 [3242804224.000000]
------------------------------------------------
 In giallo è evidenziata l'interpretazione corretta del file (contiene il numero intero 1.329.678.659 e il suo successivo: 1.329.678.660).
S
e provo ad aprire il file con il blocco note di windows (quindi interpreto il file come se fosse un testo) vedo:

che non corrisponde al valore originalmente salvato. Questo perché i 4 byte che compongono le rappresentazioni in base 256 dei numeri 1.329.678.659  e 1.329.678.660 interpretate come singoli byte corrispondono alla sequenza di numeri decimali [67][73][65][79]... che visti come codici ascii corrispondono ai simboli presenti nelle stringhe "CIAO" e "DIAO". Infatti:
1.329.678.659 =
67+73*256+65*2562+79*2563
1.329.678.660 =
68+73*256+65*2562+79*2563

Nella lettura come SHORT (ovvero uso una variabile short) gli 8 byte del file vengono letti a due a due. In HEX per i primi 2 byte avrò la coppia [43][49]. In decimale diventa [67][73] che corrisponde in notazione 256 a: 67+73*256= 18.755. Per i successivi byte si può ripetere il procedimento appena visto ottenendo così la spiegazione dei valori mostrati nello SHORT Dump


File_NR_float.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_NR_float.dat
################################################
- HEX dump :[43] [49] [41] [4F]
------------------------------------------------
- DECIMALE dump:[ 67] [ 73] [ 65] [ 79]
------------------------------------------------
- ASCII dump :[C] [I] [A] [O]
------------------------------------------------
- SHORT dump :[18755] [20289]
------------------------------------------------
- INT dump :[1329678659]
------------------------------------------------
- FLOAT dump :[3242803968.000000]
------------------------------------------------
In giallo è evidenziata l'interpretazione corretta del file (contiene infatti il numero 3.242.803.968,0002). Il numero 3.242.803.968,0002 corrisponde alla rappresentazione IEEE754 seguente (*):
0 10011110 10000010100100101000011
per cui la decodifica in ascii/hex diventa:
0 100 1111 0 100 0001 0100 1001 0100 0011
4 F 4 1 4 9 4 3
O A I C
La sequenza ascii ottenuta ("OAIC") risulta invertita rispetto a quella che in realtà vediamo ("CIAO")interpretando il file come documento testuale. Questo evidenzia come la rappresentazione in floating point venga registrata su disco partendo dal byte meno significativo (quello con potenza + bassa). In altre parole su disco la sequenza in bit reale è la seguente: 01000011 01001001 0 1000001 0 1001111

Si osservi  che il valore originale registrato era 3.242.803.968,0002 mentre nel FLOAT dump viene riportato 3.242.803.968,000000. L'errore è dovuto ad un underflow: la parte intera molto elevata con soli 32 bit porta ad una perdita di precisione nella parte decimale
(*): infatti (3242803968.0002)10 corrisponde in binario a: (11000001010010010100001100000000,
00000000000011010001101)2
la forma normalizzata è quindi 1.1000001010010010100001100000000... x 231.
Segue come esponente 158 (31+eccesso 127) = (10011110)
2
e mantissa
1000001010010010100001100000000
00000000000011010001101

 
File_NR_double.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_NR_float.dat
################################################
- HEX dump :[43] [49] [41] [4F]
------------------------------------------------
- DECIMALE dump:[ 67] [ 73] [ 65] [ 79]
------------------------------------------------
- ASCII dump :[C] [I] [A] [O]
------------------------------------------------
- SHORT dump :[18755] [20289]
------------------------------------------------
- INT dump :[1329678659]
------------------------------------------------
- FLOAT dump :[3242803968.000000]
------------------------------------------------
II numero double originale registrato è 610841384148996580000000000000000000000000000000
00000000000000000000000000,0002
. I dump proposti non forniscono la corretta interpretazione del dato poiché si fermano al float.

Utilizziamo le stesse modalità viste per i float:  la sequenza "CIAODIAO" in binario diviene (ribalto l'ordine del byte)

O A I D
0 100 1111 0100 0001 0100 1001 0100 0100
4 F 4 1 4 9 4 4
O A I C
0 100 1111 0 100 0001 0100 1001 0100 0011
4 F 4 1 4 9 4 3
corrisponde alla sequenza in 64 bit IEEE754:

0.100
11110100.0001010010010100010001001111010000010100100101000011

che corrisponde alla forma normalizzata:
1,0001010010010100010001001111010000010100100101000011 x 21531

Utilizzando nella pagina che decodifica IEEE754 la sequenza ribaltata [4F][41][49][44][4F][41][49][44] otteniamo il decimale 6,108408449500632 x 1073. (il valore normalizzato è 1.0001010010010100001101001111010000010100100101000011 x 2245)


File_NR_floatcomplex.dat e File_NR_floatcomplex.dat
OUTPUT OSSERVAZIONI
################################################
# File: .\File_NR_floatcomplex.dat
################################################
- HEX dump     :[43] [49] [41] [4F]
                [43] [49] [41] [4F]
------------------------------------------------
- DECIMALE dump:[ 67] [ 73] [ 65] [ 79]
                [ 67] [ 73] [ 65] [ 79]
------------------------------------------------
- ASCII dump   :[C] [I] [A] [O]
                [C] [I] [A] [O]
------------------------------------------------
- SHORT dump   :[18755] [20289]
                [18755] [20289]
------------------------------------------------
- INT dump     :[1329678659]
                [1329678659]
------------------------------------------------
- FLOAT dump   :[3242803968.000000]
                [3242803968.000000]

------------------------------------------------
L'analisi dei files float/double _complex segue le stesse considerazioni viste per i float/double poiché i numeri complessi vengono registrati separando la parte reale da quella immaginaria in due valori numerici semplici di tipo float/double.
La parte gialla corrisponde alla corretta interpretazione del file File_NR_floatcomplex.dat. Il primo numero è la parte reale mentre il secondo è la parte immaginaria del numero complesso salvato in origine.

Si osservi  che la parte reale e quella immaginaria originali erano 3.242.803.968,0002 mentre nel FLOAT dump vedo 3.242.803.968,000000. L'errore è dovuto ad un underflow: la parte intera molto elevata con 32 bit porta ad una perdita di precisione nella parte decimale

 

OUTPUT
################################################
# File: .\File_NR_doublecomplex.dat
################################################
- HEX dump     :[43] [49] [41] [4F]
                [44] [49] [41] [4F]
                [43] [49] [41] [4F]
                [44] [49] [41] [4F]
------------------------------------------------
- DECIMALE dump:[ 67] [ 73] [ 65] [ 79]
                [ 68] [ 73] [ 65] [ 79]
                [ 67] [ 73] [ 65] [ 79]
                [ 68] [ 73] [ 65] [ 79]
------------------------------------------------
- ASCII dump   :[C] [I] [A] [O]
                [D] [I] [A] [O]
                [C] [I] [A] [O]
                [D] [I] [A] [O]
------------------------------------------------
- SHORT dump   :[18755] [20289] [18756] [20289]
                [18755] [20289] [18756] [20289]
------------------------------------------------
- INT dump     :[1329678659] [1329678660]
                [1329678659] [1329678660]
------------------------------------------------
- FLOAT dump   :[3242803968.000000]
                [3242804224.000000]
                [3242803968.000000]
                [3242804224.000000]

------------------------------------------------