7

Is it possible to scanf a defined data type?

#include <stdio.h>
enum numberByMonth {jan=1,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec};
main(){
printf("\n");
printf("Get Number By Month (type first 3 letters): ");
enum numberByMonth stringy;
scanf("%u",stringy);
printf("Your month number is: %u",stringy);
}

Can someone help me with which datatype I should scan for? I set it to %u because gcc told me it was an unsigned integer.

Mathias
  • 171
  • 1
  • 2
  • 13

2 Answers2

5

The code you wrote should be working, but not in the way you intended, in fact, enum are treated as integer after compilation and remains no trace in the object file of your "jan,feb,mar,apr,may,jun,jul,aug,sep,oct,nov,dec", for this reason your program just parses an unsigned number from command line with scanf and returns the same number after printf.. You probably wanted this

#include <stdio.h>
#include <string.h>
char* months[] = {"jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};

int main()
{
    printf("\n");
    printf("Get Number By Month (type first 3 letters): ");
    char str[3];
    scanf("%s",str);
    int i;
    for(i=0; i<12; i++)
    {
        if(!strcmp(str,months[i]))
        {
            printf("Your month number is: %d",i+1);
        }
    }
    return 0;
}

which doesn't use enums, but it is reasonable because enums are used to preserve source readability without impairing efficiency and for this reason are threated as integers not strings, so if what you want to do is string parsing, you have to use strings because you have to compare user input with "jan", "feb" etc..

woggioni
  • 1,261
  • 1
  • 9
  • 19
0

No, it is not possible to use scanf to read an enum type -- at least, not portably.

The problem is that you do not know how big the enum is. So you don't know whether to use %d or %hd or %hhd (or, perhaps, %u or %hu or %hhu) to read the values.

If you write

scanf("%u", &stringy);

as in the question (and with the missing & added), then scanf is going to read a number and write it onto the stringy variable, but it is going to assume that stringy is an unsigned int, occupying sizeof(unsigned int) bytes of memory.

But if the compiler has decided that it can actually use a short int or maybe even just a char to hold enum numberByMonth, this is going to overwrite memory, resulting in undefined behavior.

The OP said that "gcc told me it was an unsigned integer", and that may have been true on that day, but it won't necessarily be true on another day, or under a different compiler.

The safe way to fix this, although it's cumbersome, is to use a temporary variable which you can be sure of the size of:

unsigned int tmp;
scanf("%u", &tmp);
stringy = tmp;

It would also be possible to make the assumption that enums are always going to be int-sized (that is, to assume that the compiler is never going to make them smaller), but to protect that assumption with an assertion:

assert(sizeof(stringy) == sizeof(unsigned int));
scanf("%u", &stringy);

See also What is the size of an enum in C?

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • The last suggestion is technically undefined behaviour as `%u` is only for `unsigned int`, and not other types that may happen to be the same size as `unsigned int`. – M.M Dec 09 '21 at 22:41