Book 11: Concise Names for ... Stuff
Previous | Next |
So far, we’ve learned how to use strings (char*
) and numbers (int
), and how the computer uses booleans (bool
) to represent yes or no as true or false. However, in many cases that is not enough. Often you have concepts that don’t fit into the strict form of true
or false
, and using a string of text seems awfully wasteful. After all, if you compare two strings, the computer has to compare each character of them against each other.
You could use numbers instead, that would be faster. Simply equate 1
to yes
, 2
to no
and 3
to maybe
. But of course, you’d have to remember this always during coding.
Also, what if you make a typo? One of the nice things about C is that if you type twue
instead of true
, it will complain. But if you write a string in your code, C will simply consider both the correct and the wrong spelling as valid but different. Same for a number.
That’s why the authors of C invented enumerated symbolic constants, or enum
s, for short. An enum
is simply a name for a number, or a series of numbers. To create an enum
, you write it like the following:
enum ThreefoldLogic // Pick any name you like here.
{
YES = 1,
NO = 2,
MAYBE = 3
};
from now on, you can use these three words just like you can use true
and false
. And C will see them as if you’d typed the numbers they’re equivalent to. But if you mistype one of them, it will now recognize the misspelling and balk at you. Cool, isn’t it? They don’t have to be all-uppercase either. Any valid identifier will do. Whether it be kThisIsMyCoolConstant
, or this_is_a_constant
.
But there’s more. You can even use this as a type for your variables:
enum ThreefoldLogic myVar;
myVar = YES;
The nice part about this is that variables declared like this will not accept any other values but the ones in this one enum
. So in this example, it’ll accept YES
, NO
, MAYBE
, but not true
, false
or 5
.
Note that these symbolic enumerated constants (sometimes just referred to as “constants”) are limited to being integers or characters (characters are just a different way of writing an integer to the computer). They can’t be strings.
enum EXAMPLES
{
A_NEWLINE_CHARACTER = '\n',
kTab = '\t',
kFirstCapitalLetter = 'A',
zero = 0,
one,
two
};
Also, as you can see in this example, if you don’t give a number, it will simply add one to the previous constant’s value. This goes so far that you can write:
enum {
zero,
one,
two
};
because when you don’t give a number for the first constant in an enum, it will get the number 0
.
An Alternative
One other way of declaring constants that you may encounter a lot is the old preprocessor method:
#define kConstant 15
This is basically just a global search-and-replace. Whatever is on the left side will be replaced with whatever is on the right side. This works even for function calls, but is very low-level. There are a few cases where you need #define
, like for defining a constant for a string literal or a floating point number:
#define DEFAULT_DISK_NAME "Macintosh HD"
And then there are a few more rather advanced uses that won’t be covered here. But in general you should just use enum
in your code, because it’s safer.
Typedef
We’ve seen that #define
can be used to define synonyms for pretty much everything. However, it is a very simplistic search-and-replace, and as such it is very easy to cause subtle problems. For example, if you wanted to store Mandarin text, which consists of more than 12.000 characters you wouldn’t be able to use the char type for your text strings. So instead, you’d define a new type:
#define ChineseChar int
#define ChineseString int*
Now, it would be very easy to make the following mistake:
ChineseChar charOne,
charTwo;
ChineseString stringOne,
stringTwo;
Which, after the search-and-replace, will turn out as:
int charOne,
charTwo;
int* stringOne,
stringTwo;
and as you no doubt remember from earlier in this tutorial, you’ve now accidentally declared stringTwo
as an int
instead of an int*
. You’ve essentially hidden away the fact that ChineseString
is actually a pointer. To avoid this issue, there is a special command in C, called typedef
that you can use to define an alternate name for a type. E.g.:
typedef int* ChineseString;
If we had used this typedef
instead of the #define
above, our code would have been equivalent to the following lines of code:
int* stringOne,
* stringTwo;
Because with a typedef
, you’ve actually created a completely new type, and this type implicitly is a pointer. So, if you want to define your own names for types, use typedef
, not #define
to be safe.
While we’re at it, let me mention that typedef can be used for all types. So, you can define your own names for an int
to remind people that this int
is one of all those Mandarin characters, or you can define an alternative name for a kind of pointer, or even for an enum or a struct:
typedef int ChineseChar;
typedef int* ChineseCharPointer;
typedef struct CDDatabaseEntry CDDatabaseEntry; // Now you can leave away the "struct".
typedef enum ThreefoldLogic TFL; // Okay, this is too short, although possible.
So, you can even safely use your own names for types to make your code even more readable.
Previous | Next |