Bytearray, chiarimenti

di il
11 risposte

Bytearray, chiarimenti

Salve a tutti,
ho un server in Java che riceve e trasmette tre tipi di variabili: una stringa, un intero ed un float.
Per inviare, in C, le variabili di tipo integer e float, devo convertirli in un bytearray di lunghezza 4.

Cercando su internet ho trovato due soluzioni diverse, e vorrei chiedervi il significato perchè non mi è chiaro.
La prima soluzione è questa, mi converte una variabile di tipo integer, ma non float.

unsigned char bytes[4];
int n = 3;

bytes[0] = (n >> 24) & 0xFF;
bytes[1] = (n >> 16) & 0xFF;
bytes[2] = (n >> 8) & 0xFF;
bytes[3] = n & 0xFF;
Cosa significa di preciso questo codice? e come dovrei adattare questo codice per convertire una variabile di tipo float?

La seconda soluzione, mi converte sia una variabile di tipo integer che di tipo float:

unsigned char* hexVals = malloc(sizeof(float));
int n = 2;
float f = 2,7;

hexVals[0] = ((unsigned char*)&n)[3];
hexVals[1] = ((unsigned char*)&n[2];
hexVals[2] = ((unsigned char*)&n)[1];
hexVals[3] = ((unsigned char*)&n)[0];

hexVals[0] = ((unsigned char*)&f)[3];
hexVals[1] = ((unsigned char*)&f[2];
hexVals[2] = ((unsigned char*)&f)[1];
hexVals[3] = ((unsigned char*)&f)[0];
Cosa significa quest'altro codice? e che differenza c'è tra l'altra soluzione?

11 Risposte

  • Re: Bytearray, chiarimenti

    Java? C? C++?

    In C il modo migliore per vedere la rappresentazione esadecimale di una variabile (come è memorizzata fisicamente) è usare le union e lavorare esplicitamente con il numero di bit: int non ha una lunghezza definita
    
    #include <stdio.h>
    #include <stdint.h>
    
    int main(){
        union int32{
            int32_t i;
            unsigned char b[4];
        } y = { .i = 3 };   
        
        printf("%d corrisponde a {%02X,%02X,%02X,%02X}\n", y.i, y.b[0], y.b[1], y.b[2], y.b[3]);
        
        union float32{
            float f;
            unsigned char b[4];
        } x = { .f = 2.7 };
        printf("%f corrisponde a {%02X,%02X,%02X,%02X}\n", x.f, x.b[0], x.b[1], x.b[2], x.b[3]);
    
        return 0;
    }
    
  • Re: Bytearray, chiarimenti

    Weierstrass ha scritto:


    Java? C? C++?
    Codice C.

    Sto cercando di capire il codice, ma anche questo mi è difficile da comprendere.
    I numeri, comunque, sono al rovescio, come li posso invertire?
    
    unsigned char z[4];
    z[0]=y.b[3];
    z[1]=y.b[2];
    z[2]=y.b[1];
    z[3]=y.b[0];
    
    z[0]=x.b[3];
    z[1]=x.b[2];
    z[2]=x.b[1];
    z[3]=x.b[0];
    

    Weierstrass ha scritto:


    int non ha una lunghezza definita
    Cioè? può essere anche più di 4 byte?

    Ho trovato anche quest'altro metodo per la rappresentazione:
    
    int i = 0;
    float f = 3.14;
    char *q = (char *)&f;
    printf("%f = ", f);
    for(i=0; i<sizeof(float); i++){
    	printf("%x ", *q++ & 0x0000FF);
    	}
    
    // 3.140000 = c3 f5 48 40
    
  • Re: Bytearray, chiarimenti

    Che siano invertiti è normale: quasi tutti i PC usano la notazione little endian perché è quella naturale per fare i conti. Comunque hai a disposizione un array e puoi inviare i byte nell'ordine che ti pare

    Il primo codice calcola esplicitamente la rappresentazione esadecimale di un intero dividendolo per 16^3, 16^2, 16^1 e 16 ^0 (con lo shift) e prendendo ogni volta il byte più basso (and con 0xFF). E' la stessa cosa che faresti con la rappresentazione decimale dividendo per 1000, 100, 10 e 1.

    Il secondo codice non va bene perché int non è garantito che sia a 32 bit. int32_t è garantito che lo sia.
    int lo usi quando ti servono numeri bassi e non ti interessa più di tanto sapere di quanti bit è fatta una variabile. Lo standard ti garantisce che sia lungo almeno 2 byte, solitamente è lungo 4 (come un float) ma non è detto. Float è 32 bit e double a 64 bit.

    Gli standard più recenti hanno poi rimediato introducendo i tipi in <stdint.h> dove hai il numero esatto di bit
  • Re: Bytearray, chiarimenti

    Weierstrass ha scritto:


    Che siano invertiti è normale: quasi tutti i PC usano la notazione little endian perché è quella naturale per fare i conti. Comunque hai a disposizione un array e puoi inviare i byte nell'ordine che ti pare
    Capito, grazie

    Weierstrass ha scritto:


    Il primo codice calcola esplicitamente la rappresentazione esadecimale di un intero dividendolo per 16^3, 16^2, 16^1 e 16 ^0 (con lo shift) e prendendo ogni volta il byte più basso (and con 0xFF). E' la stessa cosa che faresti con la rappresentazione decimale dividendo per 1000, 100, 10 e 1.
    E si può adattare questo codice per rappresentare anche una variabile di tipo float?
    
    unsigned char bytes[4];
    int n = 3;
    
    bytes[0] = (n >> 24) & 0xFF;
    bytes[1] = (n >> 16) & 0xFF;
    bytes[2] = (n >> 8) & 0xFF;
    bytes[3] = n & 0xFF;
    
  • Re: Bytearray, chiarimenti

    Scusa, ho scritto 16 ma intendevo 256

    Comunque l'ultimo che hai postato va bene, lo scriverei così
    
    #include <stdio.h>
    
    int main(){
        float f = 3.14;
        unsigned char *q = (unsigned char *)&f;
        printf("%f = ", f);
        for(int i=0; i<sizeof(float); i++)
    	    printf("%x ", *q++);
        return 0;
    }
    
    fa la stessa cosa della union in maniera più esplicita
  • Re: Bytearray, chiarimenti

    Weierstrass ha scritto:


    Comunque l'ultimo che hai postato va bene...
    Va bene, allora nel sorgente userò questo codice qui, grazie mille.

    Tutto questo mi serve per trasmettere una variabile di tipo integer ed una di tipo float; ho già fatto la prova e funziona, il server riceve.
    Adesso per ricevere dal server un intero ed un float, come posso procedere? sarebbe il procedimento inverso.
  • Re: Bytearray, chiarimenti

    java999 ha scritto:


    Adesso per ricevere dal server un intero ed un float, come posso procedere? sarebbe il procedimento inverso.
    Per convertire un Integer ho trovato questo codice qui, ma non è valido per convertire una variabile Float:
    
    int a = (int)(array[0] << 24 | array[1] << 16 | array[2] << 8 | array[3] & 0xff);
    printf("valore: %d", a);
    
    Per convertire una variabile Float, invece, ho trovato questo codice qui, ma non è valido per convertire una variabile Integer:
    
    union {
      char chars[4];
      float f;
    } u;
    
      u.chars[3] = array[0];
      u.chars[2] = array[1];
      u.chars[1] = array[2];
      u.chars[0] = array[3];
    float f1 = u.f;
            printf("valore: %.1f", f1);
    
    Qual'è la differenza tra questi due codici?
    Come mai, col primo codice non si può convertire una variabile Float? e come mai col secondo codice non si può convertire una variabile Integer?
  • Re: Bytearray, chiarimenti

    Per i float:
    
    #include<stdio.h>
    
    int main(int argc, char *argv[])
    {
        int dim=sizeof(float);
        unsigned char bytes[sizeof(float)];
    	
        float f = 3.14;
    	
        unsigned char *q = (unsigned char *)&f;
        
        //converto f in array di bytes
        for(int i = 0; i < dim; i++)
        {
        	bytes[i] = *q++;
        }
        
        //riottengo f
        float *p = (float*)bytes;
        float n = *p;
        printf("%f", n);
        return 0;
    }
    
    Puoi convertire e inviare come ti ha detto Weirstrass, ma ho usato l'array perché non sapevo come lo salvi una volta ricevuto (immagino sempre in un array di char).
  • Re: Bytearray, chiarimenti

    Alexv ha scritto:


    Puoi convertire e inviare come ti ha detto Weirstrass, ma ho usato l'array perché non sapevo come lo salvi una volta ricevuto (immagino sempre in un array di char).
    Mi piace quest'altra soluzione, grazie mille
  • Re: Bytearray, chiarimenti

    java999 ha scritto:


    Mi piace quest'altra soluzione, grazie mille
    Adesso che ci penso, potevi usare la più semplice (e forse anche più veloce) funzione memcpy per copiare dei blocchi di byte, senza preoccuparti della loro rappresentazione. Per i float basta usare float al posto di int e così via per tutti i tipi
    
    #include <stdio.h>
    #include <string.h>
    
    int main()
    {
        int toSend = -402;
        unsigned char byteArray[sizeof(int)];
        
        //ottengo array di byte da inviare
        memcpy(byteArray,&toSend,sizeof(int));
        
        //Ottengo numero da array di byte
        int received;
        memcpy(&received,byteArray,sizeof(int));
        printf("%d",received);
        
        return 0;
    }
    
    Tieni sempre in mente che il sizeof non ti salva se le due macchine usano lunghezze diverse per gli interi, per questo conviene sempre usare i tipi di stdint.h (es. int32_t, ecc...)
  • Re: Bytearray, chiarimenti

    Alexv ha scritto:


    Adesso che ci penso, potevi usare la più semplice (e forse anche più veloce) funzione memcpy per copiare dei blocchi di byte, senza preoccuparti della loro rappresentazione.
    Geniale, ho appena provato l'istruzione nel mio sorgente, funziona! Complimenti
    Grazie mile, quanti modi di rappresentazione abbiamo trovato
Devi accedere o registrarti per scrivere nel forum
11 risposte