2012-09-02 30 views
10

Ho un array di caratteri non firmati [248]; pieno di byte. Come 2F AF FF 00 EB AB CD EF ..... Questo array è il mio Byte Stream che memorizzo i miei dati dalla UART (RS232) come buffer.Converti byte in Int/uint in C

Ora voglio convertire i byte nei miei uint16 e int32.

In C# ho usato la classe BitConverter per fare ciò. ad esempio:

byte[] Array = { 0A, AB, CD, 25 }; 
int myint1 = BitConverter.ToInt32(bytes, 0); 
int myint2 = BitConverter.ToInt32(bytes, 4); 
int myint3 = BitConverter.ToInt32(bytes, 8); 
int myint4 = BitConverter.ToInt32(bytes, 12); 
//... 
enter code here 
Console.WriteLine("int: {0}", myint1); //output Data... 

Esiste una funzione simile in C? (No .net, io uso il compilatore KEIL perché il codice è in esecuzione su un microcontrollore)

Con saluti Sam

Solutions: Way A)

prima ho dovuto convertire o inizializzare l'array come un uint8_t ARRAY [248]; poi ho usato questo codice con il vostro aiuto:

uint32_t* myint1 = (uint32_t *)&RXBUFF[2]; //test 
uint16_t* myint2 = (uint16_t *)&RXBUFF[6]; //test3 

Attenzione: Il valore int "1985" in esadecimale è rappresentato come 0x07C1 in myint2. il Byte che ho inviato era "C1 07", quindi il microcontrollore sta modificando l'ordine dei byte

Testerò anche gli altri metodi.

WR Sam :)

risposta

8

Sì, c'è. Assumeremo che i byte sono in:

uint8_t bytes[N] = { /* whatever */ }; 

Sappiamo che, un intero a 16 bit è solo due numeri interi a 8 bit concatenati, vale a diresi ha un multiplo di 256 o in alternativa viene spostata di 8:

uint16_t sixteen[N/2]; 

for (i = 0; i < N; i += 2) 
    sixteen[i/2] = bytes[i] | (uint16_t)bytes[i+1] << 8; 
      // assuming you have read your bytes little-endian 

Analogamente per 32 bit:

uint32_t thirty_two[N/4]; 

for (i = 0; i < N; i += 4) 
    thirty_two[i/4] = bytes[i] | (uint32_t)bytes[i+1] << 8 
     | ((uint32_t)bytes[i+2] << 16 | (uint32_t)bytes[i+3] << 24; 
      // same assumption 

Se i byte vengono letti big-endian, naturalmente si inverte l'ordine :

bytes[i+1] | (uint16_t)bytes[i] << 8 

e

bytes[i+3] | (uint32_t)bytes[i+2] << 8 
    | (uint32_t)bytes[i+1] << 16 | (uint32_t)bytes[i] << 24 

Si noti che c'è una differenza tra l'endianità nel numero intero memorizzato e l'endianità dell'architettura in esecuzione. L'endianità a cui si fa riferimento in questa risposta è del numero intero memorizzato, cioè il contenuto di bytes. Le soluzioni sono indipendenti dalla endianità dell'architettura in esecuzione dal endian-ness is taken care of when shifting.

+0

e se fosse big endian? – Sam

+0

quindi si spostano i bit meno significativi invece dei bit più significativi. – devsnd

+0

@ twall, penso che tu intenda i byte. –

15

Non c'è alcuna funzione standard per farlo per voi in C. Dovrete assemblare i byte nuovamente dentro i vostri 16 e 32 bit interi te. Stai attento a Endianness!

Ecco un semplice esempio little-endian:

extern uint8_t *bytes; 
uint32_t myInt1 = bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24); 

Per un sistema big-endian, è solo l'ordine inverso:

uint32_t myInt1 = (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3]; 

Potreste essere in grado di cavarsela con:

uint32_t myInt1 = *(uint32_t *)bytes; 

Se si presta attenzione ai problemi di allineamento.

+1

Avrei assegnato ogni 'byte []' a un 'uint32_t' prima di spostarlo. Come scritto sopra, saranno castati a 'int's prima di fare i turni, ma' int' non deve essere 32 bit. –

+0

Sarebbe più sicuro, d'accordo. –

+0

Supponendo che 'byte 'sia nativo, qual è il tipo di problemi di allineamento in cui ti imbatterai? O, immagino, che tipo di situazioni rende l'allineamento un problema? – Azmisov

6

È possibile creare direttamente un puntatore uint16_t * dall'array.

uint8_t bytes[N] = { /* whatever */ }; //Shamelessly stolen from Shanbaz 

uint16_t* viewAsUint16_t = (uint16_t *)&bytes[0]; 

Ora è possibile utilizzare il puntatore per accedere agli elementi.

Si noti che questo presuppone che l'endiness sia corretto per la propria macchina. Potrebbe essere necessario eseguire il ciclo su questi uint16_t s e utilizzare funzioni come ntohs (dovrebbe essere disponibile nella maggior parte dei sistemi operativi) per correggere l'endiness.

+0

lo proverò ora. – Sam

+0

Ho provato il tuo codice ma sembra che non funzioni. Ho salvato l'output dal debugger e dalla console come un'immagine: [link] (http://s18.postimage.org/fipv7svp3/debugbyte.png) – Sam

0
  char letter = 'A'; 
      size_t filter = letter; 
      filter = (filter << 8 | filter); 
      filter = (filter << 16 | filter); 
      filter = (filter << 32 | filter); 
      printf("filter: %#I64x \n", filter); 

risultato: "Filtro: 0x4141414141414141"

0

In caso di little-endian, non puoi semplicemente usare memcpy?

memcpy((char*)&myint1, aesData.inputData[startindex], length);