[C]convertire int in byte...

fk16
Ragazzi ma come faccio a convertire una variabile di tipo int nei corrispondenti 4 byte????
Non esiste una funzione in C in grado di fare questo???? :roll:

Risposte
apatriarca
Puoi fare qualcosa come il seguente.
int i;
/* ... */
char *arr = (char *) &i;

In questo caso arr punterebbe direttamente all'intero, volendone fare una copia, il metodo più facile è quello di usare memcpy oppure usare una union. Per cosa ti serve?

fk16
Mi serve per svolgere il seguente esercizio:
Scrivere il codice di una funzione C che permetta di copiare in un vettore di 4 char i 4 byte di un numero intero

Summerwind78
Ciao

scusa ma perché non usi una union?


union myUnion
{
    unsigned int ValInt;
    unsigned char ValByte[4];
};


int main (void)
{

     union myUnion ValUnion;
     unsigned char Byte1;
     unsigned char Byte2;
     unsigned char Byte3;
     unsigned char Byte4;


     //scrivo il valore come int
     ValUnion.ValInt = 155;

     //leggo il valore in byte
     Byte1 = ValUnion.ValByte[0];
     Byte2 = ValUnion.ValByte[1];
     Byte3 = ValUnion.ValByte[2];
     Byte4 = ValUnion.ValByte[3];

}



penso che sia più semplice no?

apatriarca
Solo per fare un confronto con l'uso di memcpy:
#include <string.h>

int i;
char b[sizeof(int)]; /* potrebbe non essere uguale a 4.. */

memcpy(b, &i, sizeof(int));


E' probabilmente meglio usare una union in questo caso (o il trucco dei puntatori se si vuole modificare il valore invece che copiarlo), m è comunque molto utile conoscere memcpy. E' infatti un metodo molto semplice ed efficiente per fare copie di oggetti "complessi" (come array) o di oggetti del quale non si conosce il tipo.

Summerwind78
@apatriarca:

te ne intendi di PIC?

apatriarca
Non particolarmente, perché? Ti riferisci al "potrebbe non essere uguale a 4.."? Diciamo che nei sistemi a 32 e 64 bit gli interi sono in effetti quasi sempre a 32 bit, ma questo non è vero per i sistemi a 16bit (lo standard garantisce infatti solo una dimensione minima di 16bit). Altri tipi, come i long potrebbero invece variare tra i 32 e i 64 bit (se non ricordo male Microsoft nei suoi compilatori a 64 bit usa una dimensione per i long di 32 mentre gcc usa 64 bit).

Oppure ti riferisci all'uso di memcpy? Non sono al corrente di problemi di questa funzione con i PIC..

Summerwind78
no ho un problema con un PIC e cerco aiuto


:D

anonymous_be1147
"fk16":
Scrivere il codice di una funzione C che permetta di copiare in un vettore di 4 char i 4 byte di un numero intero

Dal testo dell'esercizio sembra che tu sia agli inizi con lo studio del C, o sbaglio? Se è così e non hai ancora imparato a usare le union o memcpy, come suggerito, forse puoi anche risolverlo con solo gli operatori & e shift (a sinistra e a destra) sui bit, per esempio con un ciclo for del tipo:

s = sizeof(int);
for (i = 0; i < s; i++) {
     shift = i * 8;
     tuo_array[i] = (unsigned char)((numero_intero & (255 << shift)) >> shift);
}

apatriarca
@anonymous_be1147: Il problema del tuo metodo è che il risultato dipende dall'endianess del sistema. Stai infatti dando per esempio per scontato che
(*(unsigned char *)&numero_intero) == (unsigned char) (numero_intero & 0xff)

Sul mio sistema funziona essendo little-endian ma, a meno di aver preso un abbaglio, non dovrebbe funzionare su un sistema big-endian. Il vantaggio delle soluzioni "più avanzate" (ma si può in realtà discutere se richiamare una funzione sia in effetti più complicato di scrivere un codice come il tuo) è che questo genere di problemi non si possono presentare.

Summerwind78
Concordo con apatriarca.

l'approccio con l'uso dello shift mi ha causato seri bachi in passato per via di un big-endian che supponevo essere little-endian

anonymous_be1147
"apatriarca":
@anonymous_be1147: Il problema del tuo metodo è che il risultato dipende dall'endianess del sistema.

Be', l'esercizio richiedeva semplicemente di "copiare in un vettore di 4 char i 4 byte di un numero intero", senza alcun riferimento all'ordine dei byte, cioè, per esempio, se il primo elemento dell'array dovesse contenere il byte meno/più significativo. In ogni caso, le operazioni sui bit sono indipendenti dall'architettura, purché eseguite con accortezza, come per altro in questo caso, usando degli unsigned.

Comunque, per dirimere la questione, ho fatto delle prove su un iMac (architettura i386 - little-endian), sfruttando l'emulatore PowerPC (big-endian) presente nel sistema. Ed ecco i risultati. Il numero testato è
0xDDCCBBAA
, tutti i programmi sono stati compilati con i comandi:

gcc -Wall -arch i386 nome_programma.c -o nome_programma_i386
gcc -Wall -arch ppc nome_programma.c -o nome_programma_ppc



    [*:1r0gukd1]Programma usando un puntatore a carattere

    #include <stdio.h>
    
    int
    main(void)
    {
            unsigned int n = 0xDDCCBBAA;
            unsigned int i;
            unsigned char *cp;
    
            cp = (unsigned char*)&n;
    
            for (i = 0; i < sizeof(int); i++) {
                printf("0x%X ", *(cp++));
            }
    
            printf("\n");
            return 0;
    }
    

    [table="puntatore-a-carattere"]Architettura x86Architettura PowerPC[tra]Output
    0xAA 0xBB 0xCC 0xDD
    0xDD 0xCC 0xBB 0xAA
    [/tra]

    Quindi in questo caso l'ordine di memorizzazione è invertito (come peraltro ci si poteva aspettare).

    [/*:m:1r0gukd1]
    [*:1r0gukd1]Programma proposto da Summerwind78, usando le union

    #include <stdio.h>
    
    union myUnion {
            unsigned int    ValInt;
            unsigned char   ValByte[4];
    };
    
    
    int
    main(void)
    {
    
            union myUnion   ValUnion;
            unsigned char   Byte1;
            unsigned char   Byte2;
            unsigned char   Byte3;
            unsigned char   Byte4;
    
    
            /* scrivo il valore come int */
            ValUnion.       ValInt = 0xDDCCBBAA;
    
            /* leggo il valore in byte */
            Byte1 = ValUnion.ValByte[0];
            printf("0x%X ", Byte1);
            Byte2 = ValUnion.ValByte[1];
            printf("0x%X ", Byte2);
            Byte3 = ValUnion.ValByte[2];
            printf("0x%X ", Byte3);
            Byte4 = ValUnion.ValByte[3];
            printf("0x%X ", Byte4);
    
            return 0;
    }
    

    [table="uso-union"]Architettura x86Architettura PowerPC[tra]Output
    0xAA 0xBB 0xCC 0xDD
    0xDD 0xCC 0xBB 0xAA
    [/tra]

    Anche in questo caso l'ordine è invertito.

    [/*:m:1r0gukd1]
    [*:1r0gukd1]Programma usando gli operatori bit a bit

    #include <stdio.h>
    
    #define NUMBER  0xDDCCBBAA
    
    int
    main(void)
    {
    
            unsigned int    i;
            unsigned int    int_size = sizeof(int);
            unsigned int    shift;
            unsigned int    num = NUMBER;
            unsigned char   A [int_size];
    
            for (i = 0; i < int_size; i++) {
                    shift = i * 0x08;
                    A[i] = (unsigned char)((num & (0xFF << shift)) >> shift);
                    printf("0x%X ", A[i]);
            }
    
            printf("\n");
    
            return 0;
    }
    

    [table="uso-bitwise"]Architettura x86Architettura PowerPC[tra]Output
    0xAA 0xBB 0xCC 0xDD
    0xAA 0xBB 0xCC 0xDD
    [/tra]

    Qui l'ordine è invece rispettato. Ribadisco comunque che l'esercizio non richiedeva affatto di controllare l'ordine dei byte.[/*:m:1r0gukd1][/list:u:1r0gukd1]
    Ovviamente, nel caso abbia preso un abbaglio clamoroso, "mi corrigerete". :)

    (Se qualcun altro vuol verificare/confrontare i risultati, e non ha un iMac, può farlo su un sistema Linux/Gnu (architetture Linux x86 e Linux PowerPC) tramite qemu.)

apatriarca
Credo che tu abbia frainteso il mio commento

Summerwind78
se apatriarca non giudica le mie soluzione quelle meno valide non riesce a dormire!!!

:D :D :D

apatriarca scherzo. Mi fai divertire ogni volta che mi commenti

apatriarca
:-D he he.. in realtà la soluzione migliore dipende dalla situazione e ho usato union in situazioni simili (anche se non del tutto equivalenti - non si lavorava su interi). Ma il problema delle union credo che sia principalmente che devi definire un tipo per fare qualcosa per il quale non è necessario. Se il passaggio tra le diverse rappresentazioni è abbastanza comune (nel caso che ho in mente rappresentavo una matrice o con un array di float o con un array di "vettori") o si tratta di un programma molto piccolo o giocattolo, allora la definizione di una union credo abbia senso, ma in altri casi credo che sia più difficilmente motivabile.

Summerwind78
concordo

anonymous_be1147
"apatriarca":
Credo che tu abbia frainteso il mio commento.[...]

Più che altro ho voluto controllare cosa succedeva su un'architettura big-endian, anche perché avevo guardato sul Deitel & Deitel, "C - Corso completo di programmazione", dopo aver letto il tuo messaggio, e lì si diceva testualmente: "I risultati delle manipolazioni dei dati dipendono dalla macchina" (ok, magari non è il massimo come riferimento, ma è quello che avevo a portata di mano in quel momento e non ricordavo più dove avevo messo il K&R), quindi una verifica sul campo si rendeva necessaria. :)

Personalmente penso che i problemi di portabilità si abbiano soltanto nel caso vengano usati dati signed con l'operatore di scorrimento a destra. Putroppo nemmeno una ricerca in Internet ha chiarito del tutto la questione (il link più attendibile trovato è quello riportato sopra). Magari sarebbe interessante sentire cosa ne pensa/sa in proposito anche qualche altro guru di questa sezione, tipo Rggb, hamming_burst, Sergio o Raptorista, tanto per fare qualche nome a caso.

P.S. Non pensavo che si potessero fare delle tabelle così..

Be', sono prodotte da BBCode personalizzati e quindi è difficile trovarli in altri forum. :)

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.