Patterns are constructs that programmers use to solve a general recurring problem. If a problem has deviated from the original, the pattern can be adapted to still be effective. In this article, we will learn a couple of them for the C programming language that I believe beginners and intermediates should know and start to apply them where ever possible.
1. Do-While Loop in Macros
If you need to use a temporary variable to store a value that will shortly be used in a macro, then it will "leak" into the local scope where it is used. The user will no longer be able to reuse the variable's name and if they do, the compiler will complain of a "redefinition". Some programmers solve this by giving a name that nobody else would use. Usually, this is a hash prefixed/suffixed onto the variable's name. The better way, in my opinion, is to use a do-while loop. When the loop goes out of scope, so do the variables and there is no "leakage". A do-while loop will always run at least once even if the while
's condition is false.
Example:
#include <stdio.h>
#define swap(type, a, b) \
do \
{ \
type temp = *b; \
*b = *a; \
*a = temp; \
} while(0) \
int main()
{
int a = 100;
int b = 200;
swap(int, &a, &b);
printf("Swapped values:\na = %d, b = %d\n", a, b);
}
2. Unions and Enums
Before we move on, let's make sure all of us understand what a union is. A union is like a structure but with one stipulation: only one member can be used at a time. You can think unions as types that change depending on what type of value we want to store. An example of using a union can found when processing tokens in a compiler/interpreter. Some tokens may be an integer, character, or string. Perfect place for a union. But there is one problem: the union doesn't give us the information about what type is currently in use. That's where enum
s come in. An enum
or enumeration is a list of names that map to a number. The first member is, by default, equal to zero and subsequent values are one plus the previous value. One of the uses of an enumeration is listing the possible values. In our case, this would be the list of possible tokens that we can accept.
Examples:
typedef enum
{
INT,
CHAR,
STRING
} TokenType;
typedef struct
{
TokenType type;
union
{
int int_value;
char char_value;
char *string_value;
} value;
} Token;
Every time we encounter a token, we figure out what type it is, set type
to the appropriate value and set the correct member in value
. When the compiler/interpreter comes back to this list of tokens to form an AST or whatever it needs to do, it can look at the type
and do the right operation.
Conclusion
Programmers can use the language's ability for leverage to solve problems that pop up every now and then. Sometimes we see two features paired and used in tandem like in the last entry.
For now, this is a standalone post but may in the future, close or far, be a series.
Top comments (0)