Newsgroup: it.comp.os.linux.development
Titolo: Manipolazione delle word in C.

Il mio problema è il seguente: vorrei poter ottenere un numero float a
partire da 2 bytes letti indipendentemente che messi insieme
costituiscono un numero a 16 bit con segno; inoltre vorrei fare
l'operazione inversa il tutto con il minimo numero di cicli macchina.
So a priori quale sia il byte basso ed il byte alto che chiamo
rispettivamente byte[0] e byte[1].
Non so a priori di quanti bytes costituito un tipo short perchè in
alcune piattaforme è 2 ed in altre è 4 (come l'int)
Per convertire una coppia di bytes ad un float ho pensato ad una
procedura del tipo:
unsigned char byte[2];
float valore;
int tmp;
/* Assegno i 2 bytes letti a byte[] */
tmp = (signed char)byte[1] * 256; //In questo modo considero anche il
segno.
if(tmp < 0) {
	tmp -= byte[0];
}
else {
	valore += byte[0];
}
Nella conversione che ho pensato sono necessari un controllo di segno
una moltiplicazione ed una addizione il che è troppo pesante per la
mia applicazione.
Per quanto riguarda la conversione da float ad una coppia di bytes non
sono riuscito a trovare alcun metodo rigoroso.
Se qualcuno mi aiutasse proponendo anche uno spezzone di codice gli
sarei molto grato.

 sarei molto grato.
Da ottimizzare, passa gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-98) -Wall
#include <stdio.h>
int twoBytesToInt( char *b) {
  return ((((int)(b[1])) << 8) & 0xffffff00) | ((int)(b[0]) & 0x000000ff);
}
float twoBytesToWord( char *b ) {
  return (float)twoBytesToInt(b);
}
char *floatTotwoBytes( float f ) {
  static char b[2];
  int i = (int)f;
  b[0] = i & 0xff;
  b[1] = (i & 0x0000ff00) >> 8;
  return b;
}
int main( int argc, char **argv ) {
  char t1[2] = {    0,      0 };        /* Zero */
  char t2[2] = { 0x64,      0 };        /* 100 */
  char t3[2] = {    0,      1 };        /* 256 */
  char t4[2] = { 0xff,   0xff };        /* -1 */
  char t5[2] = { 0xfe,   0xff };        /* -2 */
  char t6[2] = { 0xff,   0xfe };        /* -257 */
  printf( "%2x %2x => %f\n", t1[1], t1[0], twoBytesToWord(t1) );
  printf( "%2x %2x => %f\n", t2[1], t2[0], twoBytesToWord(t2) );
  printf( "%2x %2x => %f\n", t3[1], t3[0], twoBytesToWord(t3) );
  printf( "%2x %2x => %f\n", t4[1], t4[0], twoBytesToWord(t4) );
  printf( "%2x %2x => %f\n", t5[1], t5[0], twoBytesToWord(t5) );
  printf( "%2x %2x => %f\n", t6[1], t6[0], twoBytesToWord(t6) );
  printf( "-------------------------\n" );
  printf( "%2x %2x => %2x %2x\n",
          t1[1], t1[0],
          floatTotwoBytes( twoBytesToWord(t1) )[1],
          floatTotwoBytes( twoBytesToWord(t1) )[0] );
  printf( "%2x %2x => %2x %2x\n",
          t2[1], t2[0],
          floatTotwoBytes( twoBytesToWord(t2) )[1],
          floatTotwoBytes( twoBytesToWord(t2) )[0] );
  printf( "%2x %2x => %2x %2x\n",
          t3[1], t3[0],
          floatTotwoBytes( twoBytesToWord(t3) )[1],
          floatTotwoBytes( twoBytesToWord(t3) )[0] );
  printf( "%2x %2x => %2x %2x\n",
          t4[1], t4[0],
          floatTotwoBytes( twoBytesToWord(t4) )[1],
          floatTotwoBytes( twoBytesToWord(t4) )[0] );
  printf( "%2x %2x => %2x %2x\n",
          t5[1], t5[0],
          floatTotwoBytes( twoBytesToWord(t5) )[1],
          floatTotwoBytes( twoBytesToWord(t5) )[0] );
  printf( "%2x %2x => %2x %2x\n",
          t6[1], t6[0],
          floatTotwoBytes( twoBytesToWord(t6) )[1],
          floatTotwoBytes( twoBytesToWord(t6) )[0] );
  return 0;
}
Ciao,
-- 
       Roberto Divia`             Love at first sight is one of the greatest
       =============             labour-saving devices the world has ever seen.
Mailbox: C02110                 CERN-European Organization for Nuclear Research
E-mail: 
Robert...@cern.ch
           CH-1211 GENEVE 23, Switzerland

Lo ho provato, funziona e ti ringrazio molto.
Però non ho capito un cosa: provando a sostituire le due
twoBytesToInt( char *b) e  twoBytesToWord( char *b ) con una unica
float twoBytesToWord( char *b ) {
  return (float)(int)((((int)b[1] << 8) & 0xffffff00) | ((int)b[0] &
0x000000ff));
}
funziona ancora (ovviamente) ma togliendo il cast (int) prima del cast
(float) non va più bene.
Mi chiedo come mai nell'opoerazione | bit a bit tra due int mascherati
il risultato è qualcosa che va castato ad int quando lo ho già fatto
prima.
Grazie ancora.
ciao.

 (float) non va più bene.
Probabilmente perche` il risultato dell'espressione non e` un int ma un
char...
La parentesi interna ti ritorna un char e (float) si ritrova con un valore
"troncato" a 8 bit.
Per fare le cose piu` pulite, io farei:
return (float)((int)(...))
magari con dei #define (o variabili intermedie) per chiarita` e un
inline float twoBytesToWord( const char * const b ) {
per dare qualche hint al compilatore.
Creare delle variabili intermedie non penalizza il codice (almeno su
compilatori seri tipo gcc) e puo` migliorare la leggibilita`.
Sono pronto a scommettere che il codice qui sotto prende lo stesso spazio
e va alla stessa velocita` del precendente...
inline float twoBytesToWord( const char * const b ) {
  register int v;
  register int w;
  v = b[1];
  v <<= 8;
  v &= 0xffffff00;
  w = b[0];
  w &= 0x000000ff;
  v |= w;
  return (float)v;
}
Quale delle due versioni e` piu` leggibile (magari con l'aggiunta di qualche
commento)?
Nel caso tu le lo stia chiedendo, si: ho fatto (in una vita precedente) il
consulente. Pagato a ore e - talvolta - a # di linee prodotte ;-)
