Search code examples
cbytebituint32-t

Reading in exactly N bytes from standard input in C


I have to read exactly 4 bytes from standard input and then to treat it like a little endian and to display it on standard output but I don't know if what I read is exactly 4 bytes. I tried this:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <byteswap.h>

int main() {
   uint32_t f;

   printf("Enter a value :");
   scanf ("%" SCNu32, &f);
   printf("Value of integer:%d", f);
   //printf("Value of integer:%d", __bswap_32(f));

   return 0;
}

I'm not sure if this reads exactly on 4 bytes. I tried with the following integers:

input->output
123->123
12345678->12345678
123456789->123456789
4294967295->-1
4294967294->-2
4294967296->-1
1->1

I thought that by printing f it will like like this: 1234000 (value of f=1234) or 12345678 (value of f=123456789).


Solution

  • To read exactly 4 bytes from stdin, you can use fread(), getc() or scanf():

    • using fread():

      // return 1 on success, 0 on failure
      int read32(uint32_t *f) {
          return fread(f, sizeof *f, 1, stdin) == 1;
      }
      
    • using getchar() or getc():

      int read32(uint32_t *f) {
          char *p = (char *)f;
          for (size_t i = 0; i < sizeof(f); i++) {
              int c = getchar();  // or getc(stdin)
              if (c == EOF)
                  return 0;
              p[i] = c;
          }
          return 0;
      }
      
    • using scanf():

      int read32(uint32_t *f) {
          char *p = (char *)f;
          return scanf("%c%c%c%c", p, p+1, p+2, p+3) == 4;
      }
      

    Note however that stdin is open in text mode by default, which causes legacy systems to perform line ending translation, and there is no portable way to change this mode on an open stream.

    Note also that the above functions assumes the current host uses the same little endian ordering as the file. It is preferable to avoid this kind of assumption and perform a portable conversion:

    // return 1 on success, 0 on failure
    int read32(uint32_t *f, FILE *fp) {
        uint8_t a[4];
        if (fread(a, sizeof a, 1, fp) != 1)
            return 0;
        *f = ((uint32_t)a[0] <<  0) |
             ((uint32_t)a[1] <<  8) |
             ((uint32_t)a[2] << 16) |
             ((uint32_t)a[3] << 24);
        return 1;
    }