2011-01-08 19 views
8

sto provando a leggere il contenuto del file PNG.come trasmettere un array di caratteri in un singolo numero intero?

Come forse saprai, tutti i dati sono scritti in un modo a 4 byte in file png, sia di testo che di numeri. quindi se abbiamo il numero 35234 viene salvato in questo modo: [1000] [1001] [1010] [0010].

ma a volte i numeri sono più brevi, quindi i primi byte sono zero, e quando leggo l'array e lo getto da char * a numero intero ottengo il numero sbagliato. per esempio [0000] [0000] [0001] [1011] a volte i numeri vengono erroneamente interpretati come numeri negativi e in pratica lo zero!

Lasciate che vi faccia un esempio intuitivo:

char s_num[4] = {120, 80, 40, 1}; 

int t_num = 0; 

t_num = int(s_num); 

Vorrei poter spiegare bene il mio problema!

Come posso trasmettere tali array in un singolo valore intero?

ok ok ok, mi permetta di cambiare il mio codice per spiegare meglio:

char s_num[4] = {0, 0, 0, 13}; 
int t_num; 


t_num = *((int*) s_num); 
cout << "t_num: " << t_num << endl; 

qui dobbiamo ottenere 13 come il risultato, ok? ma di nuovo con questa nuova soluzione la risposta è sbagliata, puoi testare sui tuoi computer! ottengo questo numero: 218103808 che è decisamente sbagliato!

+1

La macchina è big-endian o little-endian .... leggere questo: http://en.wikipedia.org/wiki/Endianness#Big-endian – Nawaz

+1

Come si cast in base? inserisci del codice .. – Nawaz

+1

[1000] [1001] [1010] [0010] è due byte, non quattro. – TonyK

risposta

10

Si esegue il cast (char *) su (int). Che cosa si dovrebbe fare è lanciare al puntatore a intero, vale a dire

t_num = *((int*) s_num)); 

Ma in realtà si dovrebbe estrarre il codice in essa la propria funzione e fare in modo che:

  1. endianness è corretto
  2. sizeof(int) == 4
  3. Usa cast di C++ (cioè static, dynamic, const, reinterpret)
+0

cosa significa lo stesso risultato? forse dovresti spiegare, perché ti aspetti che questo dia 241 ... – Axel

+0

Oh ... quello che vuoi è solo sommare i valori in byte dei tuoi 4 caratteri. Ciò darebbe 241. La risposta di Macieks lo fa. Ma è davvero quello che vuoi fare? Mi sembra strano (non il codice, sto cercando di capire il tuo problema). – Axel

+0

ok, è vero. poooooooooof – sepisoad

6

Ipotizzando una macchina little endian con un intero a 32 bit, si può fare:

char s_num[4] = {0xAF, 0x50, 0x28, 0x1}; 
int t_num = *((int*)s_num); 

Per rompere in fasi:

  1. s_num è un array, che può essere interpretato come un puntatore al suo primo elemento (char* qui)
  2. Fusioni s_num a int* a causa di (1) - è OK per lanciare puntatori
  3. Accedere intero puntato dal puntatore cast (dereferenziazione)

Avere 0xAF come byte basso del numero intero. Esempio Fuller (codice C):

#include <stdio.h> 

int main() 
{ 
    char s_num[4] = {0xAF, 0x50, 0x28, 0x1}; 
    int t_num = *((int*)s_num); 

    printf("%x\n", t_num); 
    return 0; 
} 

Stampe:

12850af 

come previsto.

Si noti che questo metodo non è troppo portabile, in quanto assume dimensioni endianness e integer. Se si ha un compito semplice da eseguire su una singola macchina, si può farla franca, ma per qualcosa di qualità di produzione è necessario tenere in considerazione la portabilità.

Inoltre, nel codice C++ sarebbe meglio utilizzare reinterpret_cast anziché il cast in stile C.

2

Trovo che usando il set di bit std il modo più esplicito di fare conversioni (in particolare il debugging.)

Il seguente forse non è ciò che si desidera nel codice finale (troppo dettagliato forse), ma lo trovo ottimo per cercare di capire esattamente cosa sta succedendo.

http://www.cplusplus.com/reference/stl/bitset/

#include <bitset> 
#include <iostream> 
#include <string> 

int 
main (int ac, char **av) 
{ 

    char s_num[4] = {120, 80, 40, 1}; 
    std::bitset<8> zeroth = s_num[0]; 
    std::bitset<8> first = s_num[1]; 
    std::bitset<8> second = s_num[2]; 
    std::bitset<8> third = s_num[3]; 

    std::bitset<32> combo; 
    for(size_t i=0;i<8;++i){ 
    combo[i]  = zeroth[i]; 
    combo[i+8] = first[i]; 
    combo[i+16] = second[i]; 
    combo[i+24] = third[i]; 
    } 
    for(size_t i = 0; i<32; ++i) 
    { 
     std::cout<<"bits ["<<i<<"] ="<<combo.test(i)<<std::endl; 
    } 
    std::cout<<"int = "<<combo.to_ulong()<<std::endl; 
} 
+0

+1 per usare 'std :: bitset <>'; – Nawaz

-1

Lo sapevate che int di C++ troppo pieno dopo il valore 32767'th? Ciò spiegherebbe il tuo numero negativo per 35234.

La soluzione è utilizzare un tipo di dati che può gestire i valori più grandi. Vedi l'articolo Integer Overflow per ulteriori informazioni:

http://en.wikipedia.org/wiki/Integer_overflow

UPDATE: Ho scritto questo non pensando che tutti noi viviamo nel mondo moderno in cui esistono macchine a 32 bit e 64 bit e prosperare !! L'overflow di int è in effetti molto più grande della mia affermazione originale.

+3

Quale macchina hai che overflow un int su 32767? –

+0

non necessariamente così. Molte implementazioni in C++ hanno 'int' a 32 bit o anche a 64 bit che non supereranno l'intervallo dopo 32767. –

+0

@Philip:" Molti ... "lo sta dicendo gentilmente. Sarebbe difficile trovarne uno in cui è più piccolo di 32 bit in questi giorni, al di fuori del dominio incorporato, naturalmente. –

0

La conversione è fatta bene, perché non stai riassumendo questi valori ma li assegni come un unico valore. Se si desidera sommare li avete per farlo manualy:

int i; 
for (i = 0; i<4; ++i) 
    t_num += s_num[i]; 
0

EDIT: sembra che non si desidera sommare i numeri, dopo tutto. Lasciando questa risposta qui per i posteri, ma probabilmente non risponde alla domanda che vuoi porre.

si desidera sommare i valori fino, in modo da utilizzare std::accumulate:

#include <numeric> 
#include <iostream> 

int main(void) { 
    char s_num[4] = {120,80,40,1}; 
    std::cout << std::accumulate(s_num, s_num+4,0) << std::endl; 
    return 0; 
} 

produce un output:

[email protected]:~/tmp$ g++ -ansi -pedantic -W -Wall foo.cpp -ofoo 
[email protected]:~/tmp$ ./foo 
241 
+0

Non sono sicuro che questo sia quello che sta chiedendo –

+0

@Eli non credo * è * sicuro di quello che sta chiedendo. Ma questo è il risultato che il suo esempio richiede. –

+0

lo stesso è successo quando ho usato la tua soluzione – sepisoad

1

di Axel risposta violates the strict aliasing rule, almeno a partire dal C++ 14. Quindi inserisco questa risposta per i futuri utenti.


A parte le questioni endianness e dimensione, un modo sicuro è quello di utilizzare std::memcpy, cioè

unsigned char s_num[4] = {13, 0, 0, 0}; 
// ^^^^^^^^    // ^^ fix endianness issue 
// use unsigned char to avoid potential issues caused by sign bit 

int t_num; 

std::memcpy(&t_num, s_num, 4); 
Problemi correlati