3

I was doing a code review and I saw assignment of single quoted strings to enum values:

enum
{
  Option_1 = 'a',
  Option_2 = 'b'
} ;

While this makes for slightly more readable code (though the enum's meaning should be pretty much in the name of the num), it looks silly to me.

I didn't know you COULD do that and after studying it, I can see that all that happens is the binary value of the "characters" you're using gets thrown into an int.

Does anyone else do this in practice? Or is this a bad practice?

bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • 2
    BTW: Your subject line ("Assigning int x = 'a'") suggests that enums and ints are the same. While similar, they are distinct, and shouldn't be treated as interchangable. – abelenky Jul 27 '09 at 21:14
  • 2
    Also, to be picky, there is no assignment going on here. –  Jul 27 '09 at 21:21
  • Well, the individual elements within the enum are `int`'s, right? – GManNickG Jul 27 '09 at 21:25
  • @GMan Well, they are integers. –  Jul 27 '09 at 21:26
  • 1
    @GMan: See http://stackoverflow.com/questions/1122096/what-is-the-underlying-type-of-a-c-enum "What is the underlying type of a C++ enum" – maxwellb Jul 27 '09 at 21:28
  • Ah, I see now. The standard says an "unspecified int". – GManNickG Jul 27 '09 at 21:30
  • Ah dang you ninja'd me :) I just read that exact paragraph in that answer, but in my copy of the standard. – GManNickG Jul 27 '09 at 21:31
  • You will sometimes see code similar to this to convert an ascii digit into a number ('5'-'0' == 5) or to find the position in the alphabet of a letter ('h'-'a' == 7) – Dolphin Jul 27 '09 at 22:22

8 Answers8

9

It is definitely perfectly legal according to ISO C and C++ standards. And it is a fairly reasonable practice if those enum values are serialized to text (e.g. CSV) files as those characters. Otherwise, I don't see much point. I guess it could give some debugging benefits, but all good C/C++ debuggers I know can resolve enum values to corresponding symbols anyway.

Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
8

That is not a single-quoted string — it's a character literal. Using a character literal in an enum is essentially the same as assigning a char to an int — it's totally legal and can be quite useful in many situations.

Chuck
  • 234,037
  • 30
  • 302
  • 389
6

It looks ok to me, would you rather have:

enum
{
  Option_1 = 97,
  Option_2 = 98
} ;
5

chars are just 1 byte ints, so why not?

CookieOfFortune
  • 13,836
  • 8
  • 42
  • 58
  • Character literals are bigger than "char"s. This is necessary for getc() to work correctly. – dmckee --- ex-moderator kitten Jul 27 '09 at 21:15
  • That is incorrect, dmckee. According to the standard (2.13.2.1): "An ordinary character literal that contains a single c-char has type char, with value equal to the numerical value of the encoding of the c-char in the execution character set." – GManNickG Jul 27 '09 at 21:19
  • :) In your defense `getc()` *does* return an `int`, so trying to store the result with something like: `char c = getc(...);` is ill-formed. – GManNickG Jul 27 '09 at 21:24
  • This is one of the places where C and C++ differ (or at least C95). In C, a char literal is an int, which is useful in allowing extra values besides characters. In C++, a char literal is a char, which is necessary to allow operator overloading to work. – David Thornley Jul 27 '09 at 21:43
2

Unless code somewhere expects Option_1 to be 'a', I don't see the benefit.

thedz
  • 5,496
  • 3
  • 25
  • 29
2

Sometimes enums with explicit values are used where the actual value is important. If those values are "ascii value of the letter a" why shouldn't you tell the reader by assigning 'a'?

EricSchaefer
  • 25,272
  • 21
  • 67
  • 103
1

You can even assign multibyte "values" that end up being up to 32-bit ints:

enum t_f_fnf
{
    true = 'true',
    false = 'fals',
    file_not_found = 'fnf!'
};

(With a nod to the dailywtf. :) )

Jim Buck
  • 20,482
  • 11
  • 57
  • 74
  • good lord, does this actually compile? I never knew you could have more than one (non-escape) character in a character literal... – rmeador Jul 27 '09 at 21:30
  • also, does endianness come into play here? – rmeador Jul 27 '09 at 21:31
  • Yep, it compiles. I came across it myself for the first time pretty recently and couldn't believe it either. I imagine endianness comes into play as much as it would if you were assigning a full 32-bit value to each enum value. – Jim Buck Jul 27 '09 at 21:41
  • 2
    Bear in mind that "A Multicharacter literal has type int and implementation-defined value" (2.13.2, paragraph 1), so exactly what you get is implementation-defined. I'd expect endianness to matter. – David Thornley Jul 27 '09 at 21:45
  • Yes, this is EXACTLY the point of the question. Thing is, it looks silly to me to do what you've listed above. Where on dailywtf did you find this? – bobobobo Jul 27 '09 at 22:25
  • The t/f/fnf is from dailywtf, not the 4-byte "character" stuff: http://thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx . I actually see this being useful if you save these enums to a file so you can inspect the binary file and immediately see the enums. Also, if you inspect memory in a hex dump. (Or if you have a debugger that doesn't show you the enum symbol when looking at the value of a variable whose type is the enum.) – Jim Buck Jul 27 '09 at 22:34
-1

Hiya, please consider this simple example I've made for you, as you can see it is legal to use enums this way. In my case, I use them as a sort of internal constants for a class. Enjoy.

#include <iostream>

using namespace std;

class VegetableBasket
{
    enum { Max_Potatoes = 2 };  // This is a legal usage...
    enum { Max_Tomatoes = 3 };  // In here the enums serve as class's internal constants
    public :
        // Constructors
        VegetableBasket() : tomatoes(0), potatoes(0) {}
        VegetableBasket(int t, int p) : tomatoes(t), potatoes(p) 
        { 
            if(tomatoes > Max_Tomatoes) 
                tomatoes = Max_Tomatoes;
            if(potatoes > Max_Potatoes)
                potatoes = Max_Potatoes;
        }
        // Accessors
        int getMaxPotatoes() const { return Max_Potatoes; }
        int getMaxTomatoes() const { return Max_Tomatoes; }
        int getPotatoes() const { return potatoes; }
        int getTomatoes() const { return tomatoes; }
    private :
        int tomatoes;
        int potatoes;
};


void main()
{
    VegetableBasket basket1(1, 1);
    VegetableBasket basket2(5, 6);

    cout << "The basket holds : " << basket1.getMaxPotatoes() 
         << " max potatoes, and " << basket1.getMaxTomatoes()
         << " max tomatoes" << endl;

    cout << "Basket 1 holds : " << basket1.getPotatoes()
         << " potatoes and "    << basket1.getTomatoes()
         << " tomatoes" << endl;

    cout << "Basket 2 holds : " << basket2.getPotatoes()
         << " potatoes and "    << basket2.getTomatoes()
         << " tomatoes" << endl;
}
Maciek
  • 19,435
  • 18
  • 63
  • 87
  • Nice code but it would be more obviously relevant if the example constants were characters. Also, just to be nit-picky, I took a little while longer to understand what you were doing because the way you've laid out your comments for the two enum lines implied (wrongly) to me at least that you were doing one kind of thing with Max_Potatoes and another kind of thing with Max_Tomatoes. In other words the comments initially gave me the impression that Max_Potatoes was an example of something legal and Max_Tomatoes was an example of how class internal enums did something. – Bill Forster Jul 27 '09 at 23:20