Autore Topic: Leggere da un file valori di tipi diversi memorizzandoli in un'unica Struttura  (Letto 756 volte)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
« Ultima modifica: 03 Ottobre 2023, 16:24:07 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
Vi faccio notare che nel tentativo di leggere un file (nel caso specifico un file MP3) e di assegnare direttamente ad una Struttura i valori letti, l'autore della discussione nella M.L., tale Shane-2, ci dice in un suo intervento che da questa istruzione:

    Read #hfile, IDtag, ID3v1_TAG

lui ottiene un errore.
Si domanda quindi (ma lo aveva posto sin dall'inizio come questione) come fare. Come poter inserire direttamente in una "Struttura" i dati letti da un file ?

Ovviamente la nostra Wiki possiede la risposta ...e sin dal 2015 !   

Eccola qua:
http://www.gambas-it.org/wiki/index.php?title=Assegnare_direttamente_i_valori_di_dimensione_conosciuta,_letti_da_un_file,_ad_una_Struttura



« Ultima modifica: 20 Luglio 2017, 05:28:11 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
...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:
 
Codice: [Seleziona]
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......



« Ultima modifica: 20 Luglio 2017, 17:38:36 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
Il terzo errore compiuto dall'utente Shane_2 è sempre relativo alla Struttura da lui dichiarata, ma questa volta non è di natura formale, bensì sostanziale.
Lui crede/pretende che con una mera lettura del file MP3 con contenstuale caricamento nella Struttura predetta dei primi dati letti dal file, si vadano ad adagiare "de plano" i valori attinenti ai TAG del file MP3.
In questo modo dimostra, anche, di non sapere che un file MP3 non necessariamente riporta "in qualunque modo" tutti i TAG o almeno quelli principali previsti dal protocollo MP3. Talvolta un file MP3 può non possedere neppure un TAG.
Pertanto, andrebbe effettauata una dovuta verifica della presenza dei TAG nel file MP3 caricato, i quali, essendo in forma ASCII, sono facilmente individuabili.
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline Gianluigi

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 4.244
  • Tonno verde
    • Mostra profilo
Lo so, avrei potuto  meravigliarvi con effetti speciali......

 :D  :-*  :ok:
nuoto in attesa del bacio di una principessa che mi trasformi in un gambero azzurro

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.724
  • Ne mors quidem nos iunget
    • Mostra profilo
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:
Codice: [Seleziona]
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:
Codice: [Seleziona]
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



« Ultima modifica: 01 Settembre 2020, 00:46:17 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »