Thread: Enums Vs symbolic variables.

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    34

    Enums Vs symbolic variables.

    I've always used symbolic variables, typically to remove magic numbers, but also to make my code more readable. As you're aware some of the best books in C are really old so compilers have changed a lot.

    Today I stumbled across a post that said it is best to use enums rather than symbolic variables. I, as a general rule of thumb, avoid switch statements, in Java I only really used enums when I had no choice but to use a switch.

    So, to get to the point here. I'll supply some code (the code is just something I wrote for some Genuino fun, but I use symbolic variables to make it easier to change things and little more human-readable.

    Code:
    /* digial pins */
    #define RED_LED_ONE 4
    #define RED_LED_TWO 5
    #define GREEN_LED 3
    #define CURCUIT 2
    
    /* timer for delay() */
    #define TIMER 500
    
    /* function prototype */
    void flashOnStart(void);
    
    /*  hate these globals. Might put 
     *  these in the loop function and make them
     *  static (dunno if that will work, guess i'll find out). */
    int switchState = 0;
    int flash = 0;
    
    void setup() {
      // put your setup code here, to run once:
      pinMode(GREEN_LED, OUTPUT);
      pinMode(RED_LED_ONE, OUTPUT);
      pinMode(RED_LED_TWO, OUTPUT);
      pinMode(CURCUIT, INPUT);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      switchState = digitalRead(CURCUIT);
    
      for (;flash < 7; flash++)
        flashOnStart();
        
      if (switchState == LOW)
      {
        /* switch has not been pressed. */
        
        // power green LED
        digitalWrite(GREEN_LED, HIGH);
        // keep both red LEDs powered down.
        digitalWrite(RED_LED_TWO, LOW);
        delay(TIMER);
        digitalWrite(RED_LED_ONE, LOW); 
      }
      // 
      else
      {
        /* switch has been/is currently pressed. */
    
        // turn off green LED.
        digitalWrite(GREEN_LED, LOW);
        // power both red LEDS up.
        digitalWrite(RED_LED_ONE, HIGH);
        delay(TIMER);
        digitalWrite(RED_LED_TWO, HIGH);
      }
    }
    
    /* flash the green LED on and off */
    void flashOnStart(void)
    {
      if (digitalRead(GREEN_LED) == HIGH)
        digitalWrite(GREEN_LED, LOW);
      else
        digitalWrite(GREEN_LED, HIGH);
        
      delay(TIMER); 
    }

    How would I go about changing those symbolic variables to an enum?
    Last edited by Lawson; 01-06-2016 at 01:51 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Lawson
    Enums Vs symbolic variables.
    The usual term used for the latter would be "macro" or more specifically "object-like macro".

    Quote Originally Posted by Lawson
    Today I stumbled across a post that said it is best to use enums rather than symbolic variables.
    One reason why I would not call macros "symbolic variables" has to do with an advantage of enums such that you read that recommendation: after macro replacement, the symbolic name is gone, hence you may find that when you observe your program in a debugger, the symbolic names associated with enums remain, but you only see the replaced value with macros. This is an advantage in favour of the use of enums.

    Quote Originally Posted by Lawson
    How would I go about changing those symbolic variables to an enum?
    The thing is though, enums don't exist solely for named constants to be defined. Rather, they (rather loosely) form a new type that is intended to have only those enumerated values. Consequently, it is most appropriate to create an enum to enumerate (duh) some list of related constants, especially where the actual values matter less than the fact that they are unique (hence the behaviour of subsequently declared values being incremented automatically). Of course, this does not mean that it is inappropriate to specify particular values, or that we cannot have duplicate values, but if we do this, then we need to take extra care that we really do have an "enumeration" and not merely a disparate list of named constants.

    In your case, I would probably have an enum for the digital pins, e.g.,
    Code:
    enum DigitalPin {
        CURCUIT = 2,
        GREEN_LED,
        RED_LED_ONE,
        RED_LED_TWO
    };
    But I would keep TIMER as a macro since it is a separate constant. Or, seeing that you do not use TIMER to specify the size of an array, perhaps it would be appropriate to write:
    Code:
    const int TIMER = 500;
    If you really do want TIMER to be an enumerator, then it should be in an enumeration separate from the digital pins enumeration.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2015
    Posts
    34
    Quote Originally Posted by laserlight View Post
    The usual term used for the latter would be "macro" or more specifically "object-like macro".


    One reason why I would not call macros "symbolic variables" has to do with an advantage of enums such that you read that recommendation: after macro replacement, the symbolic name is gone, hence you may find that when you observe your program in a debugger, the symbolic names associated with enums remain, but you only see the replaced value with macros. This is an advantage in favour of the use of enums.


    The thing is though, enums don't exist solely for named constants to be defined. Rather, they (rather loosely) form a new type that is intended to have only those enumerated values. Consequently, it is most appropriate to create an enum to enumerate (duh) some list of related constants, especially where the actual values matter less than the fact that they are unique (hence the behaviour of subsequently declared values being incremented automatically). Of course, this does not mean that it is inappropriate to specify particular values, or that we cannot have duplicate values, but if we do this, then we need to take extra care that we really do have an "enumeration" and not merely a disparate list of named constants.

    In your case, I would probably have an enum for the digital pins, e.g.,
    Code:
    enum DigitalPin {
        CURCUIT = 2,
        GREEN_LED,
        RED_LED_ONE,
        RED_LED_TWO
    };
    But I would keep TIMER as a macro since it is a separate constant. Or, seeing that you do not use TIMER to specify the size of an array, perhaps it would be appropriate to write:
    Code:
    const int TIMER = 500;
    If you really do want TIMER to be an enumerator, then it should be in an enumeration separate from the digital pins enumeration.
    Probably getting my terminology all mixed up again. I thought it was only a macro if you did something like:

    Code:
    #define ADD(x, y) (x) + (y)
    and symbolic constant when doing something like this:
    Code:
    #define FOO 1
    And would that also mean i'd have to do one of the following:

    Code:
    enum pins { blue = 5, red = 6, yellow = 7 };
    
    int main() {
        
        enum pins out = blue;
        enum pins out1 = red;
        enum pins out3 = yellow;
        
        printf("%d %d %d\n", out, out1, out3);
        
        return 0;
    }
    or

    Code:
    #include <stdio.h>
    
    enum pins { blue = 5, red = 6, yellow = 7 };
    
    int main() {
        
        enum pins out;
        
        printf("%d %d %d\n", (out = blue), (out = red), (out = yellow));
        
        return 0;
    }
    Last one runs, but the ide isn't happy about it.

    Both ways feel very clumsy and doesn't really improve readability.

    Is there another way that I'm not privy to?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Lawson
    Probably getting my terminology all mixed up again. I thought it was only a macro if you did something like:
    Code:
    #define ADD(x, y) (x) + (y)
    That's also a macro: a function-style macro.

    Quote Originally Posted by Lawson
    And would that also mean i'd have to do one of the following:
    Well, if you don't need those variables, you could write:
    Code:
    enum pins { blue = 5, red = 6, yellow = 7 };
    
    int main() {
    
        printf("%d %d %d\n", blue, red, yellow);
    
        return 0;
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Dec 2015
    Posts
    34
    Well, if you don't need those variables, you could write:
    Code:
    Code:
    enum pins { blue = 5, red = 6, yellow = 7 };
    
    int main() {
    
        printf("%d %d %d\n", blue, red, yellow);
    
        return 0;
    }
    Didn't know you could do that. That makes a lot more sense!

    Last question (promise :P). macros are taken care of during the 'prepossessing' stage.. not sure about enums, is there a performance hit/gain using macros over enums or vice versa?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Lawson
    macros are taken care of during the 'prepossessing' stage.. not sure about enums, is there a performance hit/gain using macros over enums or vice versa?
    Enums are not specified by preprocessor directives, so they are not replaced during preprocessing. No, there should be no performance difference.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Dec 2015
    Posts
    34
    Quote Originally Posted by laserlight View Post
    Enums are not specified by preprocessor directives, so they are not replaced during preprocessing. No, there should be no performance difference.
    You're awesome, thank you very much for explaining.

  8. #8
    Registered User
    Join Date
    Dec 2015
    Posts
    34
    Quote Originally Posted by Lawson View Post
    You're awesome, thank you very much for explaining.
    Hi, me again! just one more question (i know I said the last one was the last question, but this really is).

    What you suggested works perfectly (and was the answer I was looking for). I'm trying to find out how it is possible though that you can create something like

    Code:
    enum something { blue = 1, green = 3, red = 9 };
    And simply refer to the value/something without creating an instance of it.

    ex.
    Code:
    if (blue == 1) do something;
    mind is blown, and this is awesome, just don't understand how it is working..

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    An enumeration is not a structure. Rather, an enumeration specifies an enumeration type and the members of the enumeration, i.e., the enumerators. These enumerators are constants, so they can be used as constants.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Symbolic questions
    By Ronnie11 in forum C Programming
    Replies: 1
    Last Post: 07-12-2014, 02:19 AM
  2. Symbolic Constants? O_o
    By SCRIPT_KITTEH in forum C Programming
    Replies: 6
    Last Post: 07-19-2013, 11:10 PM
  3. Help with symbolic constants
    By rpmischris in forum C Programming
    Replies: 20
    Last Post: 09-17-2012, 08:15 PM
  4. Symbolic Derivator v1.00
    By Magos in forum C++ Programming
    Replies: 1
    Last Post: 09-12-2005, 04:12 PM
  5. Symbolic Constants??
    By ACAC in forum C++ Programming
    Replies: 1
    Last Post: 09-29-2001, 06:09 PM