24

I'm trying to use this code to read values between 0 to 255 (unsigned char).

#include<stdio.h>
int main(void)
{
    unsigned char value;

    /* To read the numbers between 0 to 255 */
    printf("Please enter a number between 0 and 255 \n");
    scanf("%u",&value);
    printf("The value is %u \n",value);

    return 0;
}

I do get the following compiler warning as expected.

warning: format ‘%u’ expects type ‘unsigned int *’, but argument 2 has type ‘unsigned char *’

And this is my output for this program.

Please enter a number between 0 and 255
45
The value is 45 
Segmentation fault

I do get the segmentation fault while running this code.

What is the best way to read unsigned char values using scanf?

anatolyg
  • 26,506
  • 9
  • 60
  • 134
user1293997
  • 855
  • 5
  • 12
  • 20

2 Answers2

44

The %u specifier expects an integer which would cause undefined behavior when reading that into a unsigned char. You will need to use the unsigned char specifier %hhu.

Joe
  • 56,979
  • 9
  • 128
  • 135
  • This is really fine - but so sad gcc complains in C89/C90 mode - and further ms complains also: `%hhu` is not supported earlier than C99 as far as I know. – Bastian Ebeling Jan 30 '14 at 06:54
  • 1
    @BastianEbeling yes [here](http://www.cplusplus.com/reference/cstdio/scanf/) `hh` is marked as yellow which means it has just been introduced since C99. I wonder how to read it in C89 – phuclv Nov 25 '14 at 06:14
  • 1
    There is an example below which is now deleted that uses [`getchar()`](http://en.cppreference.com/w/cpp/io/c/getchar). – Joe Nov 25 '14 at 15:05
  • why was that getchar() example deleted, off topic? – grenix Mar 23 '17 at 09:46
2

For pre C99 I would consider writing an extra function for this just alone to avoid that segmentation fault due to undefined behaviour of scanf.

Approach:

#include<stdio.h>
int my_scanf_to_uchar(unsigned char *puchar)
{
  int retval;
  unsigned int uiTemp;
  retval = scanf("%u", &uiTemp);
  if (retval == 1)   
  {
    if (uiTemp < 256) {
      *puchar = uiTemp;
    }
    else {
      retval = 0; //maybe better something like EINVAL
    }
  }
  return retval; 
}

Then replace scanf("%u", with my_scanf_to_uchar(

Hope this is not off topic as I still used scanf and not another function like getchar :)

Another approach (without extra function)

if (scanf("%u", &uiTemp) == 1 && uiTemp < 256) { value = uitemp; }
else {/* Do something for conversion error */}
anatolyg
  • 26,506
  • 9
  • 60
  • 134
grenix
  • 623
  • 7
  • 15