Enumerated data types in C allow us to assign names to a set of integer values. This new data type can be given its own name as well. This post will discuss basic enumeration, the #define statement, values in hexadecimal, and using single bits as flags.
Enumeration:
If you have a list of possible choices which are not necessarily numbers, then enumeration can help the code show these possibilities. As an example, if you want to select only one color from a set of defined colors, then you can create an enumeration called color. Then give names like red, yellow, green, and blue to values like 0, 1, 2, and 3.
Here is an example function which has a color type as a parameter:
By creating the enum color and using typedef, color is now a unique type of data. The function choose_color creates the variable selection of type color using input and compares its value to those found in the enum color list. Notice that the term red is now interchangeable with the value 0, which means no variable should be named red.
Although colors are used in this example, enumerations can be used for many sets of choices: directions, months, locations, shapes, etc. Usually, each individual choice excludes the others; one cannot be in two locations or in two months at the same time. Luckily, whole numbers work the same way in that each value is unique.
There is also an alternative to creating an enum which is to use #define. The #define statement is similar to the find and replace option found in text editors because it will replace the first parameter with the second. If you wanted to replaced the name red with 0, you would use "#define red 0".
Here is an alternative to the previous example:
Since there is no enum called color this time, the variable selection (in function choose_color) is of type int. Also, there is no need for the typedef statement from before. While this is mostly positive, the one negative side effect is that NO variable can be named red, yellow, green, or blue because it will be replaced with 0, 1, 2, or 3. One way around this is to make the color names look less "variable-ish", like using all capital letters and possibly adding a prefix like COLOR_ to each choice.
Flags:
Unlike enumerations that exclude each other, flags use bits to allow for more possibilities. Each bit can be used to determine whether a choice is selected or not, but each selection does not exclude others. One way to access individual bits easily is to use hexadecimal values.
Where decimal uses 0-9 and binary only uses 0 and 1, hexadecimal uses 0-9 as well as a-f. The hexadecimal value a equals 10 in decimal and f is 15 in decimal. To translate a hexadecimal value into decimal, multiply each number by a power of sixteen. For example, hexadecimal c5 = c * 16^1 + 5 * 16^0 = 12 * 16 + 5 * 1 = decimal 197.
For flags, you need to use powers of two for each choice. This allows the use of individual bits (1 = 00000001, 2 = 00000010, 4 = 00000100, etc.) which can then be added together. The reason hexadecimal is helpful is because its powers of sixteen are divisible by several powers of two, and are also a power of two themselves. This allows for easier setting of bits, as seen in the following table:
This table assumes that the value is unsigned (for signed, the last three would be -128, -16, and -1). While there are patterns in the binary and decimal numbers, there is an easier to see pattern in the hexadecimal and binary numbers: each hexadecimal number affects 4 bits. We only have to remember 1, 2, 4, and 8 as powers of two.
If each choice is assigned a power of two, we can add the selected choices (or use bitwise or) and get a set of bits which correspond to the selections. To retrieve the choices from the bits, we can use bitwise and. Here is an example with some possible choices one may find in an application:
The first change you may notice is that values can be assigned to the list of enumerated values. This is useful since we must use powers of two, which are in hexadecimal for this example. The hexadecimal is not exactly useful in this case, but if another feature is added, the next hexadecimal value would be 0x10. Also, since an int is usually 32 bits, you can replace 0x10 with 0x00000010 (8 hexadecimal places, each of which control 4 bits).
Each select_features call in the main function allows us to simply list which features we want to use. We can use bitwise or (|), addition(+), or even a number to indicate the selected features. This type of input will be common in libraries like SDL, OpenGL, and OpenAL.
The input for the function select_features is not of the variable type features. An integer is used to allow operations like addition and bitwise or unlike created data types. Also, the resulting number may not be one of the power-of-two elements in the enum list. Since this is not a great use of enumeration, most libraries will use #define for flags.
Here is a similar example using #define:
The names in the program have been changed to reflect the style a library like SDL uses. The features are still given the same values: 1, 2, 4, and 8, the first four powers of two. The same selections from the previous program are made and the same results occur, however the code is slightly shorter and no new data types are introduced.
For more information about enumerated types, go to http://cplus.about.com/od/introductiontoprogramming/p/enumeration.htm and http://www.cprogramming.com/tutorial/enum.html. For a guide to hexadecimal, the page http://www.myhome.org/pg/numbers.html should help.
Thank you for reading, the next post will begin the SDL posts! This does not mean the end of the C posts, but they will be less frequent. For more C, there are the pages http://www.acm.uiuc.edu/webmonkeys/book/c_guide/, http://beej.us/guide/bgc/output/html/multipage/index.html, and http://www.cprogramming.com/tutorial/c-tutorial.html.
Enumeration:
If you have a list of possible choices which are not necessarily numbers, then enumeration can help the code show these possibilities. As an example, if you want to select only one color from a set of defined colors, then you can create an enumeration called color. Then give names like red, yellow, green, and blue to values like 0, 1, 2, and 3.
Here is an example function which has a color type as a parameter:
#include <stdio.h>
//use color in place of enum color
typedef enum color color;enum color { red, //is given value 0 yellow, // == 1 green, // 2 blue // 3 };
//a function that prints the chosen color
void choose_color(color selection) {switch(selection) { case red: //if (selection == red) printf("red selected\n"); break; case yellow: //else if (selection == yellow) printf("yellow selected\n"); break; case green: printf("green selected\n"); break; case 3: printf("blue selected\n"); break; default: //else printf("unknown selection\n"); break; } } int main() { //select three colors choose_color(red); choose_color(1); //could put yellow instead choose_color(blue); getchar(); return 0; } | output in prompt: red selected yellow selected blue selected |
By creating the enum color and using typedef, color is now a unique type of data. The function choose_color creates the variable selection of type color using input and compares its value to those found in the enum color list. Notice that the term red is now interchangeable with the value 0, which means no variable should be named red.
Although colors are used in this example, enumerations can be used for many sets of choices: directions, months, locations, shapes, etc. Usually, each individual choice excludes the others; one cannot be in two locations or in two months at the same time. Luckily, whole numbers work the same way in that each value is unique.
There is also an alternative to creating an enum which is to use #define. The #define statement is similar to the find and replace option found in text editors because it will replace the first parameter with the second. If you wanted to replaced the name red with 0, you would use "#define red 0".
Here is an alternative to the previous example:
#include <stdio.h>
#define red 0 //replace all red with 0 #define yellow 1 //yellow becomes 1 #define green 2 //green becomes 2 #define blue 3 //blue becomes 3
//a function that prints the chosen color
void choose_color(int selection) {switch(selection) { case red: //if (selection == red) printf("red selected\n"); break; case yellow: //else if (selection == yellow) printf("yellow selected\n"); break; case green: printf("green selected\n"); break; case 3: printf("blue selected\n"); break; default: //else printf("unknown selection\n"); break; } } int main() { //select three colors choose_color(red); choose_color(1); choose_color(blue); getchar(); return 0; } | output in prompt: red selected yellow selected blue selected |
Since there is no enum called color this time, the variable selection (in function choose_color) is of type int. Also, there is no need for the typedef statement from before. While this is mostly positive, the one negative side effect is that NO variable can be named red, yellow, green, or blue because it will be replaced with 0, 1, 2, or 3. One way around this is to make the color names look less "variable-ish", like using all capital letters and possibly adding a prefix like COLOR_ to each choice.
Flags:
Unlike enumerations that exclude each other, flags use bits to allow for more possibilities. Each bit can be used to determine whether a choice is selected or not, but each selection does not exclude others. One way to access individual bits easily is to use hexadecimal values.
Where decimal uses 0-9 and binary only uses 0 and 1, hexadecimal uses 0-9 as well as a-f. The hexadecimal value a equals 10 in decimal and f is 15 in decimal. To translate a hexadecimal value into decimal, multiply each number by a power of sixteen. For example, hexadecimal c5 = c * 16^1 + 5 * 16^0 = 12 * 16 + 5 * 1 = decimal 197.
For flags, you need to use powers of two for each choice. This allows the use of individual bits (1 = 00000001, 2 = 00000010, 4 = 00000100, etc.) which can then be added together. The reason hexadecimal is helpful is because its powers of sixteen are divisible by several powers of two, and are also a power of two themselves. This allows for easier setting of bits, as seen in the following table:
decimal value | binary (8 bits) | hexadecimal |
1 | 00000001 | 01 |
2 | 00000010 | 02 |
4 | 00000100 | 04 |
8 | 00001000 | 08 |
15 | 00001111 | 0f |
16 | 00010000 | 10 |
32 | 00100000 | 20 |
64 | 01000000 | 40 |
128 | 10000000 | 80 |
240 | 11110000 | f0 |
255 | 11111111 | ff |
This table assumes that the value is unsigned (for signed, the last three would be -128, -16, and -1). While there are patterns in the binary and decimal numbers, there is an easier to see pattern in the hexadecimal and binary numbers: each hexadecimal number affects 4 bits. We only have to remember 1, 2, 4, and 8 as powers of two.
If each choice is assigned a power of two, we can add the selected choices (or use bitwise or) and get a set of bits which correspond to the selections. To retrieve the choices from the bits, we can use bitwise and. Here is an example with some possible choices one may find in an application:
#include <stdio.h>
//features and enum features synonymous
typedef enum features features;
//for hexadecimal values, 0x is placed in front
enum features { //manually assign valuessubtitles = 0x01, music = 0x02, sound_effects = 0x04, multiplayer = 0x08 };
/* input a set of bits (in int form)
and the function says which features
are selected (by checking bits).
*/
void select_features(int flags) {printf("Features selected:\n"); if ((flags & subtitles) != 0) { printf("-subtitles\n"); } if ((flags & music) != 0) { printf("-music\n"); } if ((flags & 0x04) != 0) { printf("-sound effects\n"); } if ((flags & multiplayer) != 0) { printf("-multiplayer\n"); } printf("\n"); } int main() { /*make three selections of multiple
choices, zero being none*/
select_features(music | subtitles);select_features(multiplayer + music); select_features(0x0f); getchar(); return 0; } | output in prompt: Features selected: -subtitles -music Features selected: -music -multiplayer Features selected: -subtitles -music -sound effects -multiplayer |
The first change you may notice is that values can be assigned to the list of enumerated values. This is useful since we must use powers of two, which are in hexadecimal for this example. The hexadecimal is not exactly useful in this case, but if another feature is added, the next hexadecimal value would be 0x10. Also, since an int is usually 32 bits, you can replace 0x10 with 0x00000010 (8 hexadecimal places, each of which control 4 bits).
Each select_features call in the main function allows us to simply list which features we want to use. We can use bitwise or (|), addition(+), or even a number to indicate the selected features. This type of input will be common in libraries like SDL, OpenGL, and OpenAL.
The input for the function select_features is not of the variable type features. An integer is used to allow operations like addition and bitwise or unlike created data types. Also, the resulting number may not be one of the power-of-two elements in the enum list. Since this is not a great use of enumeration, most libraries will use #define for flags.
Here is a similar example using #define:
#include <stdio.h>
/* will replace the following names
with integer values */
#define FEAT_SUBS 0x01 //8-bit hexadecimal #define FEAT_MUSIC 2 //decimal #define FEAT_SOUNDFX 0x04 #define FEAT_MULTI 0x00000008 //32-bit
//tell which features are selected
void select_features(int flags) {printf("Features selected:\n"); if ((flags & FEAT_SUBS) != 0) { printf("-subtitles\n"); } if ((flags & FEAT_MUSIC) != 0) { printf("-music\n"); } if ((flags & FEAT_SOUNDFX) != 0) { printf("-sound effects\n"); } if ((flags & FEAT_MULTI) != 0) { printf("-multiplayer\n"); } printf("\n"); } int main() { /*make three selections of multiple
choices, zero being none*/
select_features(FEAT_MUSIC | FEAT_SUBS);select_features(FEAT_MULTI + FEAT_MUSIC); select_features(0x0f); getchar(); return 0; } | output in prompt: Features selected: -subtitles -music Features selected: -music -multiplayer Features selected: -subtitles -music -sound effects -multiplayer |
The names in the program have been changed to reflect the style a library like SDL uses. The features are still given the same values: 1, 2, 4, and 8, the first four powers of two. The same selections from the previous program are made and the same results occur, however the code is slightly shorter and no new data types are introduced.
For more information about enumerated types, go to http://cplus.about.com/od/introductiontoprogramming/p/enumeration.htm and http://www.cprogramming.com/tutorial/enum.html. For a guide to hexadecimal, the page http://www.myhome.org/pg/numbers.html should help.
Thank you for reading, the next post will begin the SDL posts! This does not mean the end of the C posts, but they will be less frequent. For more C, there are the pages http://www.acm.uiuc.edu/webmonkeys/book/c_guide/, http://beej.us/guide/bgc/output/html/multipage/index.html, and http://www.cprogramming.com/tutorial/c-tutorial.html.
No comments:
Post a Comment