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