View Full Version : [C] Invertire ordine dei byte di un dobule
Ciao a tutti!
Devo inserire in un sorgente una direttiva che a seconda se la macchina sul quale vado a eseguire la macchina è Little Endian o Big Endian, mi inverta l'ordine dei byte di un double. Devo scrivere una cosa del genere:
#include<endian.h>
...
#if __BYTE_ORDER==__LITTLE_ENDIAN
...
#endif
#if __BYTE_ORDER==__BIG_ENDIAN
...
#endif
Però non so come fare questa inversione. Chi può aiutarmi? Grazie :)
Devo inserire in un sorgente una direttiva che a seconda se la macchina sul quale vado a eseguire la macchina è Little Endian o Big Endian, mi inverta l'ordine dei byte di un double.A parte il little/big endian della macchina, la sequenza di 8 byte del double come ce l'hai o la devi fare??? Il problema del little/big endian sui dati ce l'hai solo quando devi leggere/scrivere un dato da qualche parte in un endian ben preciso.
Non so se mi sono spiegato ... se qualcuno mi da un file binario e mi dice che dentro c'è un double in BE, se la mia macchina è già in BE, non devo fare niente, altrimenti lo devo invertire.
Volevo capire cioè esattamente cosa devi fare.
il_luridone
30-05-2006, 16:29
Sapendo che su internet i byte più significativi vengono prima, potresti utilizzare le funzioni ntohl e htonl.
Ti copioincollo la man page:
NAME
htonl, htons, ntohl, ntohs - convert values between host and network
byte order
SYNOPSIS
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
DESCRIPTION
The htonl() function converts the unsigned integer hostlong from host
byte order to network byte order.
The htons() function converts the unsigned short integer hostshort from
host byte order to network byte order.
The ntohl() function converts the unsigned integer netlong from network
byte order to host byte order.
The ntohs() function converts the unsigned short integer netshort from
network byte order to host byte order.
On the i80x86 the host byte order is Least Significant Byte first,
whereas the network byte order, as used on the Internet, is Most Sig-
nificant Byte first.
CONFORMING TO
SUSv3.
Some systems require the inclusion of <netinet/in.h> instead of
<arpa/inet.h>.
SEE ALSO
gethostbyname(3), getservent(3)
il_luridone
30-05-2006, 16:31
Volevo capire cioè esattamente cosa devi fare.
In effetti non si capisce bene se devi invertire l'endianess del double a prescindere da quale usi il sistema, oppure se devi uniformare l'endianess del double a quella del sistema.
Sapendo che su internet i byte più significativi vengono prima, potresti utilizzare le funzioni ntohl e htonl.Uhm ... non credo proprio che possano essere utili. Un double è di 64 bit, quelle funzioni operano su 16 o 32 bit, quindi non puoi usarle, neanche "accoppiate".
Infatti quelle funzioni non posso usarle. Cmq mi serve perché dovrò leggere/scrivere double da/su file binari. Mentre per quanto riguarda gli interi e gli short questa procedura c'è (infatti sono quelle funzioni di cui mi avete parlato poco fa), per i double devo implementarla io. Devo, a prescindere, invertire l'endianness del double perché questo programma non si sa a priori dove verrà eseguito.
Ci ho pensato un pochino. Si può fare così:
#include <endian.h>
void swap_endian_double (double *pd)
{
char *p = (char*) pd;
char t;
t = p[0]; p[0] = p[7]; p[7] = t;
t = p[1]; p[1] = p[6]; p[6] = t;
t = p[2]; p[2] = p[5]; p[5] = t;
t = p[3]; p[3] = p[4]; p[4] = t;
}
void adjust_double_be (double *pd)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
swap_endian_double (pd);
#endif
}
void adjust_double_le (double *pd)
{
#if __BYTE_ORDER == __BIG_ENDIAN
swap_endian_double (pd);
#endif
}
EDIT: aggiustati i nomi delle funzioni
Grazie mille andbin. Vedendo il codice pensavo fosse molto più difficile (non che non lo sia questo). Quindi quando io dovrò scrivere su file binario swap_double() oppure devo richiamare adjust_double_from_le() (nel caso in cui sono in un'architettura le)?
Mi sorge un altro dubbio, ma un char non è più "piccolo" di un double? Cioè facendo quel cast a puntatore a char in teoria si perderebbero informazioni su quel numero, o sbaglio?
trallallero
31-05-2006, 13:15
Ciao io son nuovo (anche se seguo passivamente da tempo ...)
io ho fatto cosi:
/*------------------------------*\
DEFINISCI LA MACRO CHE "SWAPPA"
LA TROVI ANCHE SU byteswap.h
\*------------------------------*/
#define swap_64(n) ( \
(((n) & 0xff00000000000000ull) >> 56) \
| (((n) & 0x00ff000000000000ull) >> 40) \
| (((n) & 0x0000ff0000000000ull) >> 24) \
| (((n) & 0x000000ff00000000ull) >> 8 ) \
| (((n) & 0x00000000ff000000ull) << 8 ) \
| (((n) & 0x0000000000ff0000ull) << 24) \
| (((n) & 0x000000000000ff00ull) << 40) \
| (((n) & 0x00000000000000ffull) << 56) )
/*-------------------------*\
FUNZIONE CHE "SWAPPA"
\*-------------------------*/
double Swap_64( double d )
{
long long ll;
memcpy( &ll, &d, sizeof(long long) );
ll = swap_64(ll);
memcpy( &d, &ll, sizeof(long long) );
return d;
}
In pratica converti il double in long long con memcpy (ma non lo devi castare!) per far funzionare la MACRO
e poi lo riconverti in double ;)
l'ho anche testato con un mini prog in C e funzica
/*--------*\
\*--------*/
int main()
{
double d = 123.45;
int i;
char c[8];
printf( "d: <%f>\n", d );
d = Swap_64(d);
printf( "d: <%f>\n", d );
memcpy( c, &d, sizeof(long long) );
for ( i = 0; i < 8; i++ )
printf( "%X", c[i] );
puts("");
d = Swap_64(d);
printf( "d: <%f>\n", d );
memcpy( c, &d, sizeof(long long) );
for ( i = 0; i < 8; i++ )
printf( "%X", c[i] );
puts("");
return 0;
}
ciao
Scusa ma long long in ANSI C esiste? E cmq io devo fare uno swap sia se sono in BE che in LE. Quando scrivo su file binario un double, prima modifico la variabile che conterrò temporaneamente quel double e poi la converto tramite la tua swap prima di scriverla su file?
Grazie mille andbin. Vedendo il codice pensavo fosse molto più difficile (non che non lo sia questo). Quindi quando io dovrò scrivere su file binario swap_double() oppure devo richiamare adjust_double_from_le() (nel caso in cui sono in un'architettura le)?Ho aggiustato adesso i nomi alle funzioni, giusto per renderle più chiare.
Quando dovrai scrivere su file, dovrai usare la adjust_double_XX e non la swap_endian_double.
Esempio:
double d = ....;
double d_tmp;
....
d_tmp = d;
adjust_double_be (&d_tmp);
fwrite (&d_tmp, 1, sizeof (d_tmp), f);
Ho capito grazie. Speriamo che funzioni. ;)
trallallero
31-05-2006, 13:31
Scusa ma long long in ANSI C esiste? E cmq io devo fare uno swap sia se sono in BE che in LE. Quando scrivo su file binario un double, prima modifico la variabile che conterrò temporaneamente quel double e poi la converto tramite la tua swap prima di scriverla su file?
'azz! ANSI il long long ??? sai che non lo so :(
pero' ho lavorato su molto SO unix e l'ho sempre trovato.
indago ...
Mi sorge un altro dubbio, ma un char non è più "piccolo" di un double? Cioè facendo quel cast a puntatore a char in teoria si perderebbero informazioni su quel numero, o sbaglio?Sì, char è più piccolo di un double certamente! Ma io devo avere un puntatore "a byte" (un char), perché devo operare sui singoli byte che compongono il double.
Nota che io non opero mai sul valore del double direttamente, cioè non faccio alcun cast sul valore del double. Mi viene passato un puntatore a double e lo faccio diventare semplicemente un puntatore a char.
Quindi non si perde nulla.
Perfetto, grazie ancora andbin. ;)
Un'altra cosa. Questa procedura va bene anche quando devo leggere il double? Cioè a me serve che mi faccia la conversione da host byte order a network byte order e viceversa.
Un'altra cosa. Questa procedura va bene anche quando devo leggere il double? Cioè a me serve che mi faccia la conversione da host byte order a network byte order e viceversa.Credo proprio di sì. Il network byte order è big-endian.
D'accordo ma quando vado a leggere il double da file, devo richiamare questa funzione oppure no?
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.