Newsgroup: it.comp.lang.c
Titolo: endianness, questa sconosciuta

Ciao, non sono un gran programmatore (anzi, non lo sono affatto), ma
dovendo scrivere una roba in C per convertire dei file da un formato ad
un altro mi sono trovato di fronte ad un problema di endianness.
In particolare i file sono per Mac e  tutti gli offset che ci leggo
dentro sono per macchine big endian.
Dovendo scrivere anche per intel (e altre little endian) mi sa che devo
avere una funzione (o comqune una maniera) per leggere questi valori e
avere il numero giusto.
A questo punto ho due domande:
1- qual e' il metodo piu' veloce per girare dei byte? 
2- la maniera corretta (o piu' elegante) di scrivere questo programmino
e' di mettere qualcosa tipo:
#ifdef BIGENDIAN
leggi cosi' com'e'
#else 
leggi swappato
#endif
O fareste diversamente?
Grazie a chi vorra' suggerire qualcosa.
d

dawe ha scritto:

1. il metodo più veloce mi è ignoto, ma a naso potrebbe usare 
delle tabelle di lookup (che tendono a diventare enormi per 
dati multibyte). Alternativamente, vedo due strade: o usi i 
puntatori, o usi gli operatori bitwise, esempio (a spanne):
#include <stdio.h>
int main() {
    unsigned int x=0x12345678;
    unsigned int y;
    int i,j;
    unsigned char *src, *dest;
    src=(unsigned char*)&x;
    dest=(unsigned char*)&y;
    for(i=0,j=sizeof(x)-1;i<sizeof(x);i++,j--)
       dest[i]=src[j];
    printf("x = %X\ny = %X\n",x,y);
    /*alternativamente, supponendo int a 32 bit*/
    y = 0;
    y = (x <<24) | ((x <<8) & 0x00ff0000) | (x>>24) | ((x>>8) 
& 0x0000ff00);
    printf("x = %X\ny = %X",x,y);
    return 0;
}
o magari un approccio "ibribo" tabella ridotta (tipo 2^16 
entrate con precalcolati gli swap dei valori a 16 bit) + uno 
dei metodi esposti.
2. mah... :)
Ciao.


Questa e` una soluzione da usare leggendo normalmente e poi applicando 
la conversione:
#define SWAP(a,b)       ((a)^=(b),(b)^=(a),(a)^=(b))
#if defined(__linux__) || defined(VAX)
#define CONVERT_LONG(l)
#define CONVERT_WORD(l)
#endif
#ifdef sun
#define CONVERT_LONG(l)   SWAP(((char*)&l)[0], ((char*)&l)[3]);\
                           SWAP(((char*)&l)[1], ((char*)&l)[2])
#define CONVERT_WORD(l)   SWAP(((char*)&l)[0], ((char*)&l)[1])
#endif
long int numero;
fread(&numero, 1, sizeof(long), fileptr)
CONVERT_LONG(numero);
puoi anche dare un'occhiata alle funzioni/macro htonl(), htons() e le 
inverse ntohl() e ntohs() disponibile per le conversioni dei dati 
ricevuti/trasmessi in rete.
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >

Ok, grazie a tutti.
Speriamo di riuscire a fare qualcosa di utilizzabile...
d

 Non hai fatto bene i compiti. Vai dietro la lavagna.
Visto che il professore ha trovato l'errore e` cosi` gentile da farci 
sapere dove e`?
Ma non fare il solito commento che non e` portabile perché l'ho sempre 
usato e funziona benissimo :-)


 #define SWAP(a,b)       ((a)^=(b),(b)^=(a),(a)^=(b))
Non hai fatto bene i compiti. Vai dietro la lavagna.
Luca
-- 
"Accadono cose che sono come domande. Passa un minuto, oppure anni, e
 poi la vita risponde."

 O fareste diversamente?
E' "brutto" perché introduce degli ifdef nel codepath. Io farei qualcosa
di questo tipo (supponendo di lavorare con blocchi di 32bit:
#ifdef BIGENDIAN
static inline uint32_t to_bigendian(uint32_t x) {
        return x;
}
#else 
static inline uint32_t to_bigendian(uint32_t x) {
        ...
}
#endif
...
tmp = leggi32(input);
tmp = to_bigendian(tmp);
...
Il compilatore è abbastanza furbo da accorgersi che sulle macchine BE
to_bigendian non fa nulla.
Luca
-- 
"It is more complicated than you think"
                -- The Eighth Networking Truth from RFC 1925

 ha scritto nel messaggio
news:1hv9rt0.1fhg0s61avmrm2N%m...@adomain.no...

io lo swap lo faccio cosě:
typedef union VWORD
{
  uint ui;
  char b[2];
} VWORD;
char temp;
VWORD vword;
temp = vword.b[0];
vword.b[0] = vword.b[1];
vword.b[1] = temp;
cosě evito inutili shifts
ciao
ivan

 Grazie a chi vorra' suggerire qualcosa.
In genere quando ho problemi di endianness uso le funzioni ntoh e hton;
non ricordo in che header sono definiti, ma google lo saprà.
Ciao
  Andrea

>> #define SWAP(a,b)       ((a)^=(b),(b)^=(a),(a)^=(b))
Mi era sfuggito il comma che forza il sequence point. Avevo letto il
classico "a ^= b ^= a ^= b".
Luca
-- 
La vasca da bagno fu inventata nel 1850, il telefono nel 1875.
Se fossi vissuto nel 1850, avrei potuto restare in vasca per 25 anni
senza sentir squillare il telefono

 sono per macchine big endian.
Evito i #define come la peste per il byte swapping.
La soluzione piu' pulita consiste nel leggere un byte alla volta dal file.
/** Leggi 32 bit **/
uint32_t dest, i;
dest = 0;
for (i=0; i<4; i++) {
	uint8_t byte;
	fread(&byte, 1, 1, f);
	dest = (dest<<8) | byte;
}
La soluzione piu' veloce prevede una routine in assembly o una funzione
builtin del compilatore.
-- 
Legrandin