...un altro errore dell'utente shane_2, che egli estesso rileva successivamente con la frase:
"i was getting strange values eg.
a struct size of 208 when it was meant to be 128 and for some strange
reason get end of file "
sta nella dichiarazione della sua Struttura chiamata "ID3v1_TAG".
L'utente shane_2 si aspetta una dimensione di tale Struttura pari a 128 byte, invece incomprensibilmente - per lui - se ne ritrova 208 byte.
"Strange", dice lui, ma strano non è. Vediamo perché.
L'errore deriva dalla evidente mancata conoscenza del linguaggio C e dal fatto che in Gambas tutto ciò che è un carattere ASCII viene gestito con il tipo "String".
Rivediamo infatti la Struttura da lui scritta e dichiarata:
Public Struct ID3v1_TAG '(128 bytes)
Tag[3] As String 'always TAG
Title[30] As String 'title, 30 characters
Artist[30] As String 'artist, 30 characters
Album[30] As String 'album, 30 characters
Year[4] As String 'year, 4 characters
Comment[30] As String 'comment, 30 characters (or 28 if track# included)
Genre As Byte 'genre, 255 for none defined
End Struct
Come è possibile vedere, lui intende inserire in vari membri della Struttura stringhe fino a 30 caratteri. Per fare questo dichiara i relativi membri come vettori di tipo Stringa, ma lo fa dichiarando - più precisamente - per ciascun membro una variabile vettoriale di 30 elementi di tipo "String". In questo modo tenta maldestramente di emulare una soluzione tipica del C, nel quale per intercettare in quel modo uno o più caratteri vengono utilizzati array di tipo "char" (il tipo "char" in Gambas = Byte).
Shane_2 - abituato al costume Gambas - ritiene di inserire un carattere in ciascun elemento del array di tipo "String" dei membri vettoriali della Struttura. Così lui dichiara array di 30 elementi di tipo Stringa per la corrispondenza 1 elemento stringa = un carattere. ....o meglio: un carattere in un elemento di tipo Stringa del membro vettore. Si ha che occupa 30 * 8 byte di memoria per soli massimo 30 byte occupabili dai caratteri !!!
Inoltre, erroreamente crede che la dimensione della Struttura sia di 208 Byte, ma questo valore corrisponde probabilmente alla memoria occupata - ...diciamo - di default, di base da un Oggetto Struttura
Infatti, verificando con il Metodo Object.SizeOf( ) la Struttura inserendo nell'unico parametro l'identificativo della Struttura medesima, qualunque sia il numero e la tipologia dei membri della Struttura medesima, la sua dimensione sarà sempre 208 byte.
Se, invece, nel parametro del predetto Metodo inseriamo la variabile del tipo di quella Struttura, il conto sale molto su: 1024.
Si ottiene come segue, tenendo conto che in un sistema a 64 bit un tipo "String" occupa 8 Byte di memoria:
Tag[3] As String 8 byte * 3 = 24 byte occupati
Title[30] As String 8 byte * 30 = 240 byte occupati
Artist[30] As String 8 byte * 30 = 240 byte occupati
Album[30] As String 8 byte * 30 = 240 byte occupati
Year[4] As String 8 byte * 4 = 32 byte occupati
Comment[30] As String 8 byte * 30 = 240 byte occupati
Genre As Byte 1 byte * 1 = 1 byte occupato
Totale 1017 byte occupati
Poiché, però, la quantità di memoria di una Struttura non può essere diversa da un valore uguale o multiplo alla quantità di memoria occupata dal tipo maggiore presente nella tipologia dei membri della Struttra (nel nostro caso il tipo "String" = 8 byte occupati), si provvede automaticamente all'allineamento di memoria.
Al riguardo leggetevi questo mio pesantissimo mattone:
http://www.gambas-it.org/wiki/index.php?title=Gestire_con_un_Puntatore_le_Strutture_esterne
Poiché, dunque, il valore più grande di memoria occupata è quello del tipo "String" (8 byte), è necessario allineare la memoria occupata al valore multiplo immediatamente superiore al valore 1017, ossia: 1024.
Pertanto, la reale quantità di memoria occupata da quella Struttura sarà: 1024 byte !
La conferma della legge dell'allineamento dei byte occupati in memoria dai membri di una Struttura, l'avrete eliminando l'ultimo membro della Struttura dichiarata dall'utente Shane_2, ossia il Byte che occupa 1 solo byte. ...stranamente avrete il risultato di 1016 ...che è il valore multiplo inferiore più prossimo a 1024.
Ritorno ora al principio.
Volendo emulare le dichiarazioni tipiche del caso in C come avrebbe dovuto fare ?
Shane_2 avrebbe dovuto cambiare il tipo String[ ] dei membri vettoriali con il tipo Byte[ ], e successivamente alla loro valorizzazione leggerli con il loro metodo ".ToString( )".
Lo so, avrei potuto meravigliarvi con effetti speciali......
Neppure condivido l'opinione dell'utente Tony Morehen, laddove in un suo intervento afferma:
"FixedString = Bytes.ToString()
Note: Bytes.ToString stops the string conversion at the first null or at
the end of the array. Therfore, you don't have to worry about
null-terminated strings."
In sostanza lui dice che con il Metodo ".ToString( )" la lettura con conseguente conversione da valore numerico in carattere ASCII non andrà all'infinito (o meglio: fino alla fine del file letto), si fermerà bensì al primo valore 0 (zero) incontrato (0 = null terminated). ATTENZIONE: si sta parlando del valore zero = 0 = &h00 (in C: 0x00) e non del carattere stampabile "0" (che nel codice ASCII ha valore esadecimale &h30) !!!
Quanto affermato dall'utente Tony Morehen non mi risulta :-\ , come è molto facilmente riscontrabile da questo semplice esempio pratico:
Public Sub Main()
Dim bb As Byte[] = [97, 98, 99, 0, 100, 0, 0, 101, 102]
Print bb.ToString(0, bb.Count)
End
Se fosse vera la sua opinione, la lettura di questo codice si dovrebbe fermare al primo valore zero incontrato (4° elemento dell'array "bb"), mostrando solo i caratteri corrispondenti ai valori 97, 98 e 99 (ossia: a, b, c).
Ma come potere notare nel test non è così.
Ma....... esiste una modalità per ottenere il risultato pari a quello che l'utente Tony Morehen intendeva suggerire ?
Sì, esiste, ed è la funzione "String@( )" nativa di Gambas.
Questa funzione, che precipuamente è finalizzata a dereferenziare un Puntatore che punta ad un'area di memoria riservata contenente valori corrispondenti a valori ASCII standard, si blocca al primo valore zero incontrato. Mostriamo un esempio pratico riprendendo in parte l'esempio precedente:
Public Sub Main()
Dim bb As Byte[] = [97, 98, 99, 0, 100, 0, 0, 101, 102]
' Passiamo alla funzione l'indirizzo dell'area di memoria della variabile vettoriale "bb" ove sono memorizzati i valori sopra attribuiti: '
Print String@(bb.Data)
End