Conversione Big-Endian/Little-Endian

Da Gambas-it.org - Wikipedia.

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 16bit

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 ]

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 32bit

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:

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

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, 24) And &FF) Or (Shl(valore, 8) And &FF0000) Or (Shr(valore, 8) And &FF00&) Or (Shl(valore, 24) And &FF000000), 8) As String

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 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 0x67452301 da Little-Endian a Big-Endian:

Public Sub Main()
 
 Dim valore, i1, i2, i3, i4, v As Integer
  
  valore = &67452301
  
  i1 = Shr(valore, 24)
  i2 = Shl(valore, 16) And 255
  i3 = Shr(valore, 8) And 255
  i4 = valore And 255
  
  v = i1
  v = v Or Shl(i2, 8)
  v = v Or Shl(i3, 16)
  v = v Or Shl(i4, 24)

  Print Hex(v, 8), v

End

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


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