3

In terms of coding practice, in what contexts are global constants preferred to enumeration and vice versa?

For example, let's say I needed a way to express a variety of tile sprites at a global scope. I could do...

const int TILE_RED = 0; 
const int TILE_GREEN = 1; 
const int TILE_BLUE = 2; 
const int TILE_CENTER = 3; 
const int TILE_TOP = 4;
const int TILE_TOPRIGHT = 5; 
const int TILE_RIGHT = 6; 
const int TILE_BOTTOMRIGHT = 7; 
const int TILE_BOTTOM = 8; 
const int TILE_BOTTOMLEFT = 9; 
const int TILE_LEFT = 10;
const int TILE_TOPLEFT = 11; 

or

enum Tile { TILE_RED, TILE_GREEN, TILE_BLUE, TILE_CENTER, TILE_TOP, TILE_TOPRIGHT
TILE_RIGHT, TILE_BOTTOMRIGHT, TILE_BOTTOM, TILE_BOTTOMLEFT, TILE_LEFT, TILE_TOPLEFT };

Obviously we prefer constants and enums to macros, but what about when it comes down to constants and enums? What situations prefer what? I read here that constant objects pose a small risk of making your program slower, but I'd like to hear others' thoughts.

I used this example in particular because it's a large set of related objects - the cat's pajamas for enumeration.

trikker
  • 2,651
  • 10
  • 41
  • 57

6 Answers6

4

Two related advantages of enums are their self-documenting nature, and the fact that they keep the namespace clearer. Basically enums are like bundles of semantically related constants, within their own namespace. By using enums in intefaces you indicate implicitly what set of values would be expected.

Edit: Correction! (I've been doing too much C# and such lately, and not enough C/C++ !)
With C and C++ the identifiers in an enumeration are scoped like ordinary variables and constants and must therefore be distinct that any other identifier in the same scope, including identifiers within other enumeration lists. This is unlike more modern languages where the enum introduces its own namespace. The notion that C/C++ enums help with keeping the namespace tidy is consequently incorrect. Thank you, Michael Burr, for pointing that out.

The main drawback of enums is that they are not as readily portable. A constant type and value are unambiguously defined, there's less clarity with enums.

mjv
  • 73,152
  • 14
  • 113
  • 156
  • How does an enum keep the namespace clearer than a const? They both end up in the namespace they're in - you can't have a const and an enum with the same name at the same namespace 'level'. Remember, what's important here is name of the the actual enumeration (eg., `TILE_RED`), not the name of the enum type (eg., `enum Tile`). – Michael Burr Oct 04 '09 at 17:40
  • @Michael Burr Oops! As said in my edit, I've been taking some C# features for granted. You are right, in C/C++, the enums do not introduce their own namespace, and therefore the indentifiers in an enum list must share the namespace of the underlying scope. The advantages of enums in C/C++ are therefore rather slim, no wonder I didn't use them all that much, especially considering the potential interop issues with mixed compiler projects. Thank you for keeping me honest. – mjv Oct 05 '09 at 01:37
4

One nice thing about enums is that they're portable between C and C++, while const items can't be used in C in all the places you might like (Like array declarations). So for headers that I'd like to work in either C or C++ I have tended to use enums in preference to const declarations or macro definitions. Actually I've tended to use them regardless of whether the header is intended only for C++ or not (one less decision I have to think about).

Having the type of the enum be ambiguous isn't a problem very often - if you're overloading based on various different integral types you'll have potential problems with enums, and in that case const items would probably be better. But I can't remember the last time I've needed different behavior for different types of the same number (ie., treating 5U differently than 5 or 5L). I think that type of overloading is only really seen in puzzle/interview types of problems, or it's code that'll breed bugs anyway whether you use enums or not.

So bottom line is I'd prefer enums - but good luck getting your co-workers to stop using macros. Using macros for named constants is pretty well ingrained in the C/C++ culture and even though they pollute the namespace in a big way, there's not enough real word problems to convince many people to even think about changing the habit.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
3

Use enums when the value of the constant is either not important or sequential as in your example.

Use constants if you need special constant values assigned to the identifier.

Lothar
  • 12,537
  • 6
  • 72
  • 121
1

The biggest advantage of an enum is that it can be enforced by the compiler, such is not the case with a constant.

Joanne C
  • 1,115
  • 6
  • 10
  • AFAIK a c compiler is not allowed to do this as a enum typed variable defines an integer type of some bit length (depending on the enum) but not an subrange of the integer type. – Lothar Oct 04 '09 at 04:32
0

Non explicit enums can cause some platform compatibility issues, and also, they're not type safe. Global constants are type safe and generally preferred. However, if you overlook this, enums are generally use for related things and constants for more unrelated things.

Example when you would use enums:

enum Colors {
COLOR_RED=0xFF0000,
COLOR_GREEN=0x00FF00,
COLOR_BLUE=0x0000FF
}  

Example when you would use global consts:

volatile const void *VRAM=0x00FC0000;

Finally, my advice is that if you really care about platform compatibility, then use global consts.

aviraldg
  • 9,531
  • 6
  • 41
  • 56
  • 2
    "Non explicit enums can cause some platform compatibility issues" - examples please. Also what do you mean by "not type safe", and how are global constants any more so? – Pavel Minaev Oct 04 '09 at 04:22
  • The "non explicit" simply meant that enums have no type. The platform compatibility issue was found on linux boxes and a fix was made to glibc for this. A good compiler will report it to you if you try to implicit cast a const. – aviraldg Oct 04 '09 at 05:16
  • Could you point to some information about the libc platform compatibility fix you've mentioned? I'd like to learn about this. – Michael Burr Oct 04 '09 at 17:43
0

When there is no special reason for backward compatibility, I prefer forward compatibility. In this case, using global consts is more compiler-independent, but I vote for enums for several reasons:
1. consts may have different types. All it takes is a bad search-replace when you want to replace the type of your enum. It can lead to some unexpected effects (consider signed/unsigned and value size). in enums a single type is enforced.
2. strongly typed enums are introduced in C++0x. There are some implementations for this already in C++.
3. enums, IMHO, are very difficult to write in an unclear way. You can't say that on consts (spread across several files, etc.).

BTW, If you use const, I prefer using static consts inside a class scope (and not global).

Oren S
  • 1,820
  • 1
  • 19
  • 33