Differenze tra le versioni di "Conversione Big-Endian/Little-Endian"
(9 versioni intermedie di uno stesso utente non sono mostrate) | |||
Riga 7: | Riga 7: | ||
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'' | + | è 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. | + | 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 [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== | |
− | |||
Questa modalità è in sintassi così espressa: | Questa modalità è in sintassi così espressa: | ||
− | Hex((Shr( | + | Hex((Shr(''valore'', 8) And &FF) Or (Shl(''valore'', 8) And &FF00&), 4) As String |
− | + | V'è da sottolineare che: | |
− | <BR> | + | <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> - 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== | |
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((( | + | Hex(((''valore'' \ CInt(2 ^ 8)) And &FF) Or ((''valore'' * CInt(2 ^ 8)) And &FF00&), 4) As String |
oppure | oppure | ||
− | Hex((( | + | 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'': | 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() | ||
Riga 52: | Riga 51: | ||
v = s1 | v = s1 | ||
− | v = v Or s2 | + | v = v Or Shl(s2, 8) |
Print Hex(v, 4), v | Print Hex(v, 4), v | ||
Riga 61: | Riga 60: | ||
− | + | =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 | + | 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) | ||
− | + | 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== | |
− | |||
Questa modalità è in sintassi così espressa: | Questa modalità è in sintassi così espressa: | ||
− | Hex((Shr( | + | 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) | ||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | =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" | |
+ | |||
+ | <FONT Color=gray>' ''uint32_t ntohl (uint32_t __netlong)'' | ||
+ | ' ''Converts the unsigned integer netlong from network byte order to host byte order.''</font> | ||
+ | Private Extern ntohl(__netlong As Integer) As Integer | ||
+ | |||
+ | <FONT Color=gray>' ''uint16_t ntohs (uint16_t __netshort)'' | ||
+ | ' ''Converts the unsigned short integer netshort from network byte order to host byte order.''</font> | ||
+ | Private Extern ntohs(__netshort As Short) As Short | ||
+ | |||
+ | |||
'''Public''' Sub Main() | '''Public''' Sub Main() | ||
− | Dim | + | Dim i As Integer |
+ | Dim c As Short | ||
+ | |||
+ | i = ntohl(&01020304) | ||
+ | Print Hex(i, 8) | ||
− | + | c = ntohs(&0908) | |
+ | Print Hex(c, 4) | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
'''End''' | '''End''' | ||
− | + | ||
− | |||
=Note= | =Note= | ||
− | [1 | + | [1] 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.
Indice
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. »