cscanfformat-specifierslength-modifiers

About conversion specifier of scanf in C


I have a question about conversion specifier of scanf in C.

#include <stdio.h>

int main(void)
{
    int num1;
    scanf("%hhd",&num1);
    printf("%d \n",num1);
}

Since I have typed "%hhd" as the conversion specifier in scanf function, when my input is "128", I expect -128 to be stored in num1. But the result shows that 128 is stored in num1.

Why does this happen even though I have used "%hhd" to specify input as char int?


Solution

  • Step 1 With scanf() issues: check results. Unless the return value indicates something was written into num1, printing it does not reflect user input.

    int num1;
    if (scanf("%hhd",&num1) == 1) {
      printf("%d \n",num1);
    }
    

    Step 2: Enable compiler warnings. Saves time.

    if (scanf("%hhd",&num1) == 1) {
    // warning: format '%hhd' expects argument of type 'signed char *', 
    // but argument 2 has type 'int *' [-Wformat=]
    

    Why does this happen even though I have used "%hhd" to specify input as char int?

    This in not about integer types: int versus char. The is about pointers: int * versus signed char *. "%hhd" in scanf() matches a pointer: signed char * (or unsigned char * or char *), not an int nor char.

    Code passed &num1, a int *. Compliant code would pass a signed char *.

    If a conversion specification is invalid, the behavior is undefined. C11 §7.21.6.2 13

    That is it. Code broke the rules, expected behavior does not occur. Use the correct type.

    signed char num1;
    if (scanf("%hhd",&num1) == 1) {
      printf("%d \n",num1);
    }
    

    If code must save the result in an int:

    int num1;
    signed char ch1;
    if (scanf("%hhd",&ch1) == 1) {
      num1 = ch1;
      printf("%d \n",num1);
    }