C legge lo stdin binario

Sto cercando di build un simulatore di pipeline di istruzioni e sto avendo un sacco di problemi per iniziare. Quello che devo fare è leggere il binario da stdin, e poi memorizzarlo in qualche modo mentre manipolo i dati. Ho bisogno di leggere in blocchi di esattamente 32 bit uno dopo l’altro.

Come faccio a leggere in blocchi di esattamente 32 bit alla volta? In secondo luogo, come posso conservarlo in seguito per la manipolazione?

Ecco cosa ho ottenuto finora, ma esaminando i blocchi binari che ho letto più avanti, non sembra giusto, non penso di leggere esattamente 32 bit come ho bisogno.

char buffer[4] = { 0 }; // initialize to 0 unsigned long c = 0; int bytesize = 4; // read in 32 bits while (fgets(buffer, bytesize, stdin)) { memcpy(&c, buffer, bytesize); // copy the data to a more usable structure for bit manipulation later // more stuff buffer[0] = 0; buffer[1] = 0; buffer[2] = 0; buffer[3] = 0; // set to zero before next loop } fclose(stdin); 

Come faccio a leggere a 32 bit alla volta (sono tutti 1/0, non newline ecc.) E in che modo lo memorizzo, è char[] ok?

EDIT: Sono in grado di leggere il binario, ma nessuna delle risposte produce i bit nell’ordine corretto – sono tutti storpiati, sospetto di endianness e problemi di lettura e spostamento di 8 bit in giro (1 carattere) alla volta – questo ha bisogno di lavorare su Windows e C …?

Quello di cui hai bisogno è freopen() . Dalla pagina di manuale:

Se filename è un puntatore nullo, la funzione freopen () tenterà di modificare la modalità del stream con quella specificata dalla modalità, come se il nome del file attualmente associato al stream fosse stato utilizzato. In questo caso, il descrittore di file associato allo stream non deve essere chiuso se la chiamata a freopen () ha esito positivo. È definito dall’implementazione quali cambiamenti di modalità sono consentiti (se presenti) e in quali circostanze.

Fondamentalmente, il meglio che puoi davvero fare è questo:

 freopen(NULL, "rb", stdin); 

Questo riaprirà lo stdin per essere lo stesso stream di input, ma in modalità binaria. Nella modalità normale, la lettura da stdin su Windows convertirà \r\n (Windows newline) nel singolo carattere ASCII 10. Utilizzando la modalità "rb" disabilita questa conversione in modo da poter leggere correttamente i dati binari.

freopen() restituisce un filehandle, ma è il valore precedente (prima di metterlo in modalità binaria), quindi non usarlo per nulla. Dopo, usa fread() come è stato menzionato.

Per quanto riguarda le tue preoccupazioni, tuttavia, potresti non leggere in “32 bit” ma se usi fread() in 4 char (che è il meglio che puoi fare in C- char è garantito che sia almeno 8 bit ma alcune piattaforms storiche e embedded hanno 16 bit di bit (alcuni ne hanno addirittura 18 o peggio)). Se usi fgets() non leggerete mai in 4 byte. Ne leggerete almeno 3 (a seconda che qualcuno di loro sia newline), e il 4 ° byte sarà '\0' perché le stringhe C sono nul-terminate e fgets() nul-termina ciò che legge (come una buona funzione ). Ovviamente, questo non è quello che vuoi, quindi dovresti usare fread() .

Prendi in considerazione l’utilizzo SET_BINARY_MODE macro setmode e della modalità setmode :

 #ifdef _WIN32 # include  # include  # define SET_BINARY_MODE(handle) setmode(handle, O_BINARY) #else # define SET_BINARY_MODE(handle) ((void)0) #endif 

Maggiori dettagli sulla macro SET_BINARY_MODE qui: ” Gestione dei file binari tramite I / O standard ”

Maggiori dettagli su setmode qui: “_setmode ”

Fgets () è tutto sbagliato qui. È finalizzato al testo ASCII leggibile dall’uomo, terminato da caratteri di fine riga, non da dati binari, e non ti offre ciò che ti serve.

Recentemente ho fatto esattamente quello che vuoi usando la chiamata read () . A meno che il tuo programma non abbia esplicitamente chiuso stdin, per il primo argomento (il descrittore di file), puoi usare un valore costante di 0 per stdin. Oppure, se sei su un sistema POSIX (Linux, Mac OS X o qualche altra variante moderna di Unix), puoi usare STDIN_FILENO.

Non so quale sistema operativo si esegue, ma in genere non è ansible “aprire lo stdin in binario”. Puoi provare cose come

 int fd = fdreopen (fileno (stdin), outfname, O_RDONLY | OPEN_O_BINARY); 

per cercare di forzarlo. Quindi utilizzare

 uint32_t opcode; read(fd, &opcode, sizeof (opcode)); 

Ma in realtà non l’ho provato da solo. 🙂

Ho dovuto separare la risposta insieme dai vari commenti delle persone gentili sopra, quindi ecco un esempio pienamente funzionante che funziona – solo per Windows, ma probabilmente puoi tradurre le cose specifiche di Windows sulla tua piattaforma.

 #include "stdafx.h" #include "stdio.h" #include "stdlib.h" #include "windows.h" #include  #include  int main() { char rbuf[4096]; char *deffile = "c:\\temp\\outvideo.bin"; size_t r; char *outfilename = deffile; FILE *newin; freopen(NULL, "rb", stdin); _setmode(_fileno(stdin), _O_BINARY); FILE *f = fopen(outfilename, "w+b"); if (f == NULL) { printf("unable to open %s\n", outfilename); exit(1); } for (;; ) { r = fread(rbuf, 1, sizeof(rbuf), stdin); if (r > 0) { size_t w; for (size_t nleft = r; nleft > 0; ) { w = fwrite(rbuf, 1, nleft, f); if (w == 0) { printf("error: unable to write %d bytes to %s\n", nleft, outfilename); exit(1); } nleft -= w; fflush(f); } } else { Sleep(10); // wait for more input, but not in a tight loop } } return 0; } 

fread () si adatta meglio alla lettura di dati binari.

Sì, il char array è OK, se hai intenzione di elaborarli a byte.

Ho avuto ragione la prima volta, tranne, avevo bisogno di ntohl … C Endian Conversion: poco alla volta