Search code examples
cscanfunsigned-char

A problem with the behaviour of scanf when data type is unsigned char


So I have no idea why this behavior is observed:

#include <stdio.h>

int main()
{
    unsigned char c;
    char d;
    scanf("%hhu", &d);
    printf("%c\n", d);

    return 0;
}

If I remember correctly %hhu is for unsigned char. If I input almost any character like a, or b the answer is nothing and d gets the value 0. But if I input 97 then d prints the value a (so ASCII is converted to char). This clearly not the case when the data type is char. I can just input the character directly and it is stored.

Also in the slight modification of this code

#include <stdio.h>

int main()
{
    unsigned char c;
    char d;
    int g;
    scanf("%hhu", &d);
    printf("%c\n", d);
    scanf("%d", &g);
    printf("%d is g\n", g);

    return 0;
}

If I give first input as a character like w or a then it just skips the second scanf, but if the input is a number then it works normally.


Solution

  • a is not a valid input for %hhu. An integer (in the Math sense) is expected. If we add error checking (code below), we get:

    $ gcc -Wall -Wextra -pedantic a.c -o a && ./a
    a
    Number of assigned variables: 0
    Can't read: Invalid input
    
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) {
        unsigned char c;
    
        int rv = scanf("%hhu", &c);
        if (rv == EOF) {
           if (ferror(stdin)) {
              perror("Can't read");
           } else {
              fprintf(stderr, "Can't read: Premature EOF\n");
           }
    
           exit(1);
        }
    
        printf("Number of assigned variables: %d\n", rv);
    
        if (rv < 1) {
           fprintf(stderr, "Can't read: Invalid input\n");
           exit(1);
        }
    
        printf("%hhu\n", c);
    
        return 0;
    }
    

    Invalid input stays in the handle's buffer to be obtained by future reads. So an error in a early scanf can cause later scanf to fail.

    If you wish to proceed after an error, you could simply read until you get a LF to clear any "junk" in the buffer.

    void read_stdin_to_eol(void) {
       while (1) {
          int ch = getchar();
          if (ch == '\n' || ch == EOF)
             return ch;
       }
    }