Differenze tra le versioni di "Conversione Big-Endian/Little-Endian"

Da Gambas-it.org - Wikipedia.
(13 versioni intermedie di uno stesso utente non sono mostrate)
Riga 3: Riga 3:
 
La differenza tra i due sistemi è data dall'ordine, con il quale i byte costituenti il dato vengono memorizzati:
 
La differenza tra i due sistemi è data dall'ordine, con il quale i byte costituenti il dato vengono memorizzati:
 
* ''Big-Endian'' è il tipo di memorizzazione che inizia (da sinistra verso destra) dal byte più significativo (che è quello posto a sinistra) e termina con il byte meno significativo;
 
* ''Big-Endian'' è il tipo di memorizzazione che inizia (da sinistra verso destra) dal byte più significativo (che è quello posto a sinistra) e termina con il byte meno significativo;
* ''Little-Endian'' è il tipo di memorizzazione che inizia (da destra verso sinistra) dal byte meno significativo (che è quello posto a destra) e termina con il byte più significativo.
+
* ''Little-Endian'' è il tipo di memorizzazione che inizia (da destra verso sinistra) dal byte meno significativo (che è quello posto a destra) e termina con il byte più significativo. Quindi in sostanza nel sistema ''Little-Endian'' l'ordine dei byte nell'indirizzo di memoria è invertito ripetto al sistema ''Big-Endian''.
  
 
Se ad esempio abbiamo il valore decimale 1234567, la memorizzazione nella seguente forma esadecimale:
 
Se ad esempio abbiamo il valore decimale 1234567, la memorizzazione nella seguente forma esadecimale:
 
  12 D6 87
 
  12 D6 87
è di tipo ''Big-Endian'', mentre una memorizzazione nella forma:
+
è di tipo ''Big-Endian''.
 +
 
 +
Invece la memorizzazione di quello stesso numero nella forma:
 
  87 D6 12
 
  87 D6 12
è, invece, di tipo ''Little-Endian.
+
è, invece, di tipo ''Little-Endian''.
  
  
In taluni casi particolari, pertanto, possiamo riscontrare che alcuni valori vengono scritti per la memorizzazione in modalità ''Little-Endian'', e che, pertanto, per comprenderne il reale significato/valore, devono essere convertiti in forma ''Big-Endian''. Possiamo, per converso, avere valori che, memorizzati inizialmente nel formato esadecimale della forma ''Big-Endian'', debbano essere convertiti in forma ''Little-Endian'', affinché altri pogrammi possano comprendere il loro reale significato e restituire quindi il vero valore. |[[#Note|1]]|
+
In taluni casi particolari, pertanto, possiamo riscontrare che alcuni valori vengono scritti per la memorizzazione in modalità ''Little-Endian'', e che, pertanto, per comprenderne il reale significato/valore, devono essere convertiti in forma ''Big-Endian''. Possiamo, per converso, avere valori che, memorizzati inizialmente nel formato esadecimale della forma ''Big-Endian'', debbano essere convertiti in forma ''Little-Endian'', affinché altri pogrammi possano comprendere il loro reale significato e restituire quindi il vero valore.
  
  
  
==Conversione ''Big-Endian''/''Little-Endian'' e viceversa di un valore a 16bit==
+
=Conversione ''Big-Endian''/''Little-Endian'' e viceversa di un valore a 16-bit=
 
La formula astratta per ottenere la conversione ''Big-Endian''/''Little-Endian'' e viceversa di un valore a 16bit (= 2 byte, ossia di tipo ''Short'') può essere la seguente (anche se [http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c le modalità sono molteplici] per ottenere la conversione):
 
La formula astratta per ottenere la conversione ''Big-Endian''/''Little-Endian'' e viceversa di un valore a 16bit (= 2 byte, ossia di tipo ''Short'') può essere la seguente (anche se [http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c le modalità sono molteplici] per ottenere la conversione):
 
  ((valore >> 8) & 0x00FF) | ((valore << 8) & 0xFF00)
 
  ((valore >> 8) & 0x00FF) | ((valore << 8) & 0xFF00)
Riga 24: Riga 26:
 
* Uso dell'operatore ''OR'' combinato con operazione di scorrimento dei bit a sinistra.
 
* Uso dell'operatore ''OR'' combinato con operazione di scorrimento dei bit a sinistra.
  
 
+
==Uso delle funzioni di scorrimento dei bit a destra ed a sinistra==
===Uso delle funzioni di scorrimento dei bit a destra ed a sinistra===
 
 
Questa modalità è in sintassi così espressa:
 
Questa modalità è in sintassi così espressa:
  Hex((Shr(&''valore'', 8) And &FF) Or (Shl(&''valore'', 8) And &FF00&), 4) As String
+
  Hex((Shr(''valore'', 8) And &FF) Or (Shl(''valore'', 8) And &FF00&), 4) As String
Se ''valore'' è proprio una variabile di tipo ''Short'', allora il suo valore va convertito in decimale, ad esempio così:
+
Vda sottolineare che:
<BR>''Val("&" & valore).
+
<BR> - il il valore ''&FF00&'' necessita assolutamente alla fine del carattere '''&''', poiché, se non lo si ponesse, avremmo come risultato un valore in esadecimale di 3 byte ! <SUP>[ [[#Note|Nota 1]] ]</sup>
<BR>V'è da sottolineare che il il valore ''&FF00&'' necessita assolutamente alla fine del carattere '''&''', poiché, se non lo si ponesse, avremmo come risultato un valore in esadecimale di 3 byte ! |[[#Note|2]]|
+
<BR> - se il valore convertito assume un valore massimo supportato in Gambas dal tipo "Short" (ossia superiore al valore espresso in esadecimale &7FFF), allora la variabile "valore" dovrà essere dichiarata come tipo <SPAN Style="text-decoration:underline">Integer</span>.
 
 
  
===Uso di esplicite operazioni matematiche===
+
==Uso di esplicite operazioni matematiche==
 
Se si vorranno utilizzare esplicite operazioni matematiche anziché funzioni Gambas, si potrà adoperare la seguente formula:
 
Se si vorranno utilizzare esplicite operazioni matematiche anziché funzioni Gambas, si potrà adoperare la seguente formula:
  Hex(((&''valore'' \ CInt(2 ^ 8)) And &FF) Or ((&''valore'' * CInt(2 ^ 8)) And &FF00&), 4) As String
+
  Hex(((''valore'' \ CInt(2 ^ 8)) And &FF) Or ((''valore'' * CInt(2 ^ 8)) And &FF00&), 4) As String
 
oppure
 
oppure
  Hex(((&''valore'' \ CInt(2 ^ 8)) And &FF) Or CShort(((&''valore'' * CInt(2 ^ 8)) And &FF00)), 4) As String
+
  Hex(((''valore'' \ CInt(2 ^ 8)) And &FF) Or CShort(((''valore'' * CInt(2 ^ 8)) And &FF00)), 4) As String
 
 
  
===Uso dell'operatore ''OR'' con operazione di scorrimento dei bit a sinistra===
+
==Uso dell'operatore ''OR'' con operazione di scorrimento dei bit a sinistra==
Mostriamo un esempio pratico con l'operatore ''OR''  combinato con operazione di scorrimento dei bit a sinistra, in cui convertiremo il valore esadecimale ''0x2301'' da ''Little-Endian'' a ''Big-Endian'':
+
Mostriamo un esempio pratico con l'operatore ''OR''  combinato con operazione di scorrimento dei bit a sinistra, in cui convertiremo il valore esadecimale ''0x2301'' di tipo ''Short'' da ''Little-Endian'' a ''Big-Endian'':
 
  '''Public''' Sub Main()
 
  '''Public''' Sub Main()
 
   
 
   
   Dim valore As String = "2301"
+
   Dim valore, s1, s2, v As Short
  Dim b1, b2, v As Short
+
 
  Dim s As String
+
  valore = &2301
+
 
+
   s1 = Shr(valore, 8)
   b1 = CShort(Val("&" & Left(valore, 2)))
+
   s2 = valore And 255
+
 
   b2 = CShort(Val("&" & Right(valore, 2)))
+
   v = s1
+
   v = v Or Shl(s2, 8)
   v = b1
+
 
   v = v Or b2 * (CInt(2 ^ 8))
+
  Print Hex(v, 4), v
 
      
 
      
  Print Hex(v, 4), v
 
 
 
  '''End'''
 
  '''End'''
 
Questo algoritmo è valido anche per la conversione contraria: da ''Big-Endian'' a ''Little-Endian''.
 
Questo algoritmo è valido anche per la conversione contraria: da ''Big-Endian'' a ''Little-Endian''.
Riga 63: Riga 60:
  
  
==Conversione ''Big-Endian''/''Little-Endian'' e viceversa di un valore a 32bit==
+
=Conversione ''Big-Endian''/''Little-Endian'' e viceversa di un valore a 32-bit=
La formula astratta per ottenere la conversione ''Big-Endian''/''Little-Endian'' di un valore a 32bit (= 4 byte, ossia di tipo ''Integer'') può essere la seguente:
+
La formula astratta per ottenere la conversione ''Big-Endian''/''Little-Endian'' di un valore intero a 32-bit (''Integer'') può essere la seguente:
 
  ((valore >> 24) & 0xff) | ((valore << 8) & 0xff0000) | ((valore >> 8) & 0xff00) | ((valore << 24) & 0xff000000)
 
  ((valore >> 24) & 0xff) | ((valore << 8) & 0xff0000) | ((valore >> 8) & 0xff00) | ((valore << 24) & 0xff000000)
che in Gambas potremo tradurre, utilizzando uno dei seguenti metodi:
+
La suddetta formula in Gambas potrà essere tradotta utilizzando uno dei seguenti metodi:
 
* funzioni di scorrimento dei bit a destra ed a sinistra;
 
* funzioni di scorrimento dei bit a destra ed a sinistra;
 
* esplicite operazioni matematiche;
 
* esplicite operazioni matematiche;
 
* Uso dell'operatore ''OR'' combinato con operazione di scorrimento dei bit a sinistra.
 
* Uso dell'operatore ''OR'' combinato con operazione di scorrimento dei bit a sinistra.
  
 
+
==Uso delle funzioni di scorrimento dei bit a destra ed a sinistra==
===Uso delle funzioni di scorrimento dei bit a destra ed a sinistra===
 
 
Questa modalità è in sintassi così espressa:
 
Questa modalità è in sintassi così espressa:
  Hex((Shr(&''valore'', 24) And &FF) Or (Shl(&''valore'', 8) And &FF0000) Or (Shr(&''valore'', 8) And &FF00&) Or (Shl(&''valore'', 24) And &FF000000), 8) A String
+
  Hex((Shr(''valore'', 24) And &FF) Or (Shl(''valore'', 8) And &FF0000) Or (Shr(''valore'', 8) And &FF00&) Or (Shl(''valore'', 24) And &FF000000), 8) As String
 +
oppure
 +
Hex((Shr(valore, 24)) Or (Shl(i, 8) And &FF0000) Or (Shr(valore, 8) And &FF00&) Or (Shl(valore, 24)), 8) As String
 +
Va sottolineato che, se dalla conversione, il numero assumerà un valore superiore a quello supportato in Gambas dal tipo "Integer" (ossia superiore al valore espresso in esadecimale &7FFFFF), allora sarà opportuno dichiarare la variabile "valore" come tipo <SPAN Style="text-decoration:underline">Long</span>.
 +
==Uso di esplicite operazioni matematiche==
 +
Se si vorranno utilizzare esplicite operazioni matematiche anziché funzioni Gambas, si potrà adoperare la seguente formula:
 +
Hex(((''valore'' \ CInt(2 ^ 24)) And &FF) Or ((''valore'' * CInt(2 ^ 8)) And &FF0000) Or ((''valore'' \ CInt(2 ^ 8)) And &FF00&) Or ((''valore'' * CInt(2 ^ 24)) And &FF000000), 8)
 +
oppure quest'altra:
 +
Hex(((''valore'' \ CInt(2 ^ 24)) And &FF) Or ((''valore'' * CInt(2 ^ 8)) And &FF0000) Or CShort(((''valore'' \ CInt(2 ^ 8)) And &FF00)) Or ((''valore'' * CInt(2 ^ 24)) And &FF000000), 8)
  
  
===Uso di esplicite operazioni matematiche===
 
Se si vorranno utilizzare esplicite operazioni matematiche anziché funzioni Gambas, si potrà adoperare la seguente formula:
 
Hex(((&''valore'' \ CInt(2 ^ 24)) And &FF) Or ((&''valore'' * CInt(2 ^ 8)) And &FF0000) Or ((&''valore'' \ CInt(2 ^ 8)) And &FF00&) Or ((&''valore'' * CInt(2 ^ 24)) And &FF000000), 8)
 
oppure quest'altra:
 
Hex(((&''valore'' \ CInt(2 ^ 24)) And &FF) Or ((&''valore'' * CInt(2 ^ 8)) And &FF0000) Or CShort(((&''valore'' \ CInt(2 ^ 8)) And &FF00)) Or ((&''valore'' * CInt(2 ^ 24)) And &FF000000), 8)
 
  
 +
=Rotazione dei byte mediante le funzioni ''ntohl( )'' e ''ntohs( )''=
 +
Mediante le funzioni esterne ''ntohl( )'' e ''ntohs( )'', dichiarate nel file header "''/usr/include/netinet/in.h''", è possibile ottenere la rotazione dei byte rispettivamente di un valore di tipo ''Intero'' (32 bit) e di uno valore di tipo ''Intero Corto'' (16 bit).
  
===Uso dell'operatore ''OR'' con operazione di scorrimento dei bit a sinistra===
+
Mostriamo un semplice esempio:
Mostriamo un esempio pratico con l'operatore ''OR''  combinato con operazione di scorrimento dei bit a sinistra, in cui convertiremo il valore esadecimale ''0x67452301'' da ''Little-Endian'' a ''Big-Endian'':
+
  Library "libc:6"
  '''Public''' Sub Main()
 
 
  Public Sub Main()
 
 
   
 
   
  Dim valore As String = ''67452301''
+
<FONT Color=gray>' ''uint32_t ntohl (uint32_t __netlong)''
  Dim i1, i2, i3, i4, v As Integer
+
' ''Converts the unsigned integer netlong from network byte order to host byte order.''</font>
 
+
Private Extern ntohl(__netlong As Integer) As Integer
 
   
 
   
  i1 = CInt(Val("&" & Left(valore, 2)))
+
<FONT Color=gray>' ''uint16_t ntohs (uint16_t __netshort)''
  i2 = CInt(Val("&" & Mid(valore, 3, 2)))
+
' ''Converts the unsigned short integer netshort from network byte order to host byte order.''</font>
  i3 = CInt(Val("&" & Mid(valore, 5, 2)))
+
Private Extern ntohs(__netshort As Short) As Short
  i4 = CInt(Val("&" & Right(valore, 2)))
 
  v = i1
 
  v = v Or i2 * (CInt(2 ^ 8))
 
  v = v Or i3 * (CInt(2 ^ 16))
 
  v = v Or i4 * (CInt(2 ^ 24))
 
 
   
 
   
  Print Hex(v, 8), v
 
 
   
 
   
 +
'''Public''' Sub Main()
 +
 
 +
  Dim i As Integer
 +
  Dim c As Short
 +
 
 +
  i = ntohl(&01020304)
 +
  Print Hex(i, 8)
 +
 
 +
  c = ntohs(&0908)
 +
  Print Hex(c, 4)
 +
 
 
  '''End'''
 
  '''End'''
Questo algoritmo è valido anche per la conversione contraria: da ''Big-Endian'' a ''Little-Endian''.
+
 
 
  
  
 
=Note=
 
=Note=
[1] Vedi anche la pagina "''[[Leggere_un_numero_in_big-endian_a_dimensione_fissa|Leggere un numero in big-endian a dimensione fissa]]''"
+
[1] Interpellato al riguardo Benoît Minisini ha così spiegato il problema e suggerito la soluzione:
 
 
[2] Interpellato al riguardo Benoît Minisini ha così spiegato il problema e suggerito la soluzione:
 
 
<BR>« ''Because of weird Visual Basic compatibility, &FF00 is sign-extended, i.e. &FF00 = &FFFFFF00''
 
<BR>« ''Because of weird Visual Basic compatibility, &FF00 is sign-extended, i.e. &FF00 = &FFFFFF00''
 
<BR>''To prevent automatic sign-extension, write &FF00& (with an extra '&' at the end).''
 
<BR>''To prevent automatic sign-extension, write &FF00& (with an extra '&' at the end).''

Versione delle 20:14, 31 ott 2021

Big-Endian e Little-Endian sono due differenti modalità per memorizzare dati di dimensione superiore al semplice byte.

La differenza tra i due sistemi è data dall'ordine, con il quale i byte costituenti il dato vengono memorizzati:

  • Big-Endian è il tipo di memorizzazione che inizia (da sinistra verso destra) dal byte più significativo (che è quello posto a sinistra) e termina con il byte meno significativo;
  • Little-Endian è il tipo di memorizzazione che inizia (da destra verso sinistra) dal byte meno significativo (che è quello posto a destra) e termina con il byte più significativo. Quindi in sostanza nel sistema Little-Endian l'ordine dei byte nell'indirizzo di memoria è invertito ripetto al sistema Big-Endian.

Se ad esempio abbiamo il valore decimale 1234567, la memorizzazione nella seguente forma esadecimale:

12 D6 87

è di tipo Big-Endian.

Invece la memorizzazione di quello stesso numero nella forma:

87 D6 12

è, invece, di tipo Little-Endian.


In taluni casi particolari, pertanto, possiamo riscontrare che alcuni valori vengono scritti per la memorizzazione in modalità Little-Endian, e che, pertanto, per comprenderne il reale significato/valore, devono essere convertiti in forma Big-Endian. Possiamo, per converso, avere valori che, memorizzati inizialmente nel formato esadecimale della forma Big-Endian, debbano essere convertiti in forma Little-Endian, affinché altri pogrammi possano comprendere il loro reale significato e restituire quindi il vero valore.


Conversione Big-Endian/Little-Endian e viceversa di un valore a 16-bit

La formula astratta per ottenere la conversione Big-Endian/Little-Endian e viceversa di un valore a 16bit (= 2 byte, ossia di tipo Short) può essere la seguente (anche se le modalità sono molteplici per ottenere la conversione):

((valore >> 8) & 0x00FF) | ((valore << 8) & 0xFF00)

che in Gambas potremo tradurre, utilizzando uno dei seguenti metodi:

  • funzioni di scorrimento dei bit a destra ed a sinistra;
  • esplicite operazioni matematiche;
  • Uso dell'operatore OR combinato con operazione di scorrimento dei bit a sinistra.

Uso delle funzioni di scorrimento dei bit a destra ed a sinistra

Questa modalità è in sintassi così espressa:

Hex((Shr(valore, 8) And &FF) Or (Shl(valore, 8) And &FF00&), 4) As String

V'è da sottolineare che:
- il il valore &FF00& necessita assolutamente alla fine del carattere &, poiché, se non lo si ponesse, avremmo come risultato un valore in esadecimale di 3 byte ! [ Nota 1 ]
- se il valore convertito assume un valore massimo supportato in Gambas dal tipo "Short" (ossia superiore al valore espresso in esadecimale &7FFF), allora la variabile "valore" dovrà essere dichiarata come tipo Integer.

Uso di esplicite operazioni matematiche

Se si vorranno utilizzare esplicite operazioni matematiche anziché funzioni Gambas, si potrà adoperare la seguente formula:

Hex(((valore \ CInt(2 ^ 8)) And &FF) Or ((valore * CInt(2 ^ 8)) And &FF00&), 4) As String

oppure

Hex(((valore \ CInt(2 ^ 8)) And &FF) Or CShort(((valore * CInt(2 ^ 8)) And &FF00)), 4) As String

Uso dell'operatore OR con operazione di scorrimento dei bit a sinistra

Mostriamo un esempio pratico con l'operatore OR combinato con operazione di scorrimento dei bit a sinistra, in cui convertiremo il valore esadecimale 0x2301 di tipo Short da Little-Endian a Big-Endian:

Public Sub Main()

 Dim valore, s1, s2, v As Short
  
  valore = &2301
  
  s1 = Shr(valore, 8)
  s2 = valore And 255
  
  v = s1
  v = v Or Shl(s2, 8)
  
  Print Hex(v, 4), v
   
End

Questo algoritmo è valido anche per la conversione contraria: da Big-Endian a Little-Endian.


Conversione Big-Endian/Little-Endian e viceversa di un valore a 32-bit

La formula astratta per ottenere la conversione Big-Endian/Little-Endian di un valore intero a 32-bit (Integer) può essere la seguente:

((valore >> 24) & 0xff) | ((valore << 8) & 0xff0000) | ((valore >> 8) & 0xff00) | ((valore << 24) & 0xff000000)

La suddetta formula in Gambas potrà essere tradotta utilizzando uno dei seguenti metodi:

  • funzioni di scorrimento dei bit a destra ed a sinistra;
  • esplicite operazioni matematiche;
  • Uso dell'operatore OR combinato con operazione di scorrimento dei bit a sinistra.

Uso delle funzioni di scorrimento dei bit a destra ed a sinistra

Questa modalità è in sintassi così espressa:

Hex((Shr(valore, 24) And &FF) Or (Shl(valore, 8) And &FF0000) Or (Shr(valore, 8) And &FF00&) Or (Shl(valore, 24) And &FF000000), 8) As String

oppure

Hex((Shr(valore, 24)) Or (Shl(i, 8) And &FF0000) Or (Shr(valore, 8) And &FF00&) Or (Shl(valore, 24)), 8) As String

Va sottolineato che, se dalla conversione, il numero assumerà un valore superiore a quello supportato in Gambas dal tipo "Integer" (ossia superiore al valore espresso in esadecimale &7FFFFF), allora sarà opportuno dichiarare la variabile "valore" come tipo Long.

Uso di esplicite operazioni matematiche

Se si vorranno utilizzare esplicite operazioni matematiche anziché funzioni Gambas, si potrà adoperare la seguente formula:

Hex(((valore \ CInt(2 ^ 24)) And &FF) Or ((valore * CInt(2 ^ 8)) And &FF0000) Or ((valore \ CInt(2 ^ 8)) And &FF00&) Or ((valore * CInt(2 ^ 24)) And &FF000000), 8)

oppure quest'altra:

Hex(((valore \ CInt(2 ^ 24)) And &FF) Or ((valore * CInt(2 ^ 8)) And &FF0000) Or CShort(((valore \ CInt(2 ^ 8)) And &FF00)) Or ((valore * CInt(2 ^ 24)) And &FF000000), 8)


Rotazione dei byte mediante le funzioni ntohl( ) e ntohs( )

Mediante le funzioni esterne ntohl( ) e ntohs( ), dichiarate nel file header "/usr/include/netinet/in.h", è possibile ottenere la rotazione dei byte rispettivamente di un valore di tipo Intero (32 bit) e di uno valore di tipo Intero Corto (16 bit).

Mostriamo un semplice esempio:

Library "libc:6"

' uint32_t ntohl (uint32_t __netlong)
' Converts the unsigned integer netlong from network byte order to host byte order.
Private Extern ntohl(__netlong As Integer) As Integer

' uint16_t ntohs (uint16_t __netshort)
' Converts the unsigned short integer netshort from network byte order to host byte order.
Private Extern ntohs(__netshort As Short) As Short


Public Sub Main()
 
 Dim i As Integer
 Dim c As Short
 
  i = ntohl(&01020304)
  Print Hex(i, 8)
  
  c = ntohs(&0908)
  Print Hex(c, 4)
  
End


Note

[1] Interpellato al riguardo Benoît Minisini ha così spiegato il problema e suggerito la soluzione:
« Because of weird Visual Basic compatibility, &FF00 is sign-extended, i.e. &FF00 = &FFFFFF00
To prevent automatic sign-extension, write &FF00& (with an extra '&' at the end).
Otherwise, I don't know where your data comes from, but Swap$() does endianness conversion provided that each integer is stored inside a string. »


Riferimenti