Reputation: 671
I am actualy using something like this to make constansts for my error function. Is this fine or should I do this somehow else?
// declares 1 and 0 as a FALSE and TRUE
#define TRUE 1
#define FALSE !TRUE
// declares "error types"
const enum {
SYNTAX = 0,
ZERO_OPERATOR = 1,
ZERO_MINUS = 2
};
How I am using "error types" constants in code:
If (!something) error(SYNTAX); // there is a switch in error function which prints the error
Upvotes: 1
Views: 735
Reputation: 123578
There are several different ways to define symbolic constants in C:
#define FOO something
enum { FOO=1, BAR=10, BLETCH=100 };
const double PI=3.14159265359;
Each has its pros and cons.
Preprocessor macros are basically just text replacements, and can be used for simple values:
#define FOO 10
#define STR "This is a test"
#define PI 3.14159265359
or for more complex expressions
#define BAR (FOO * PI + BLETCH)
The problem is that preprocessor macros are replaced during the preprocessing stage, so after your code is compiled the symbols FOO
, STR
, PI
, and BAR
no longer exist (which can make assembly-level debugging difficult), and they don't obey scoping rules (i.e., if you create the macro within a function, it's visibility won't be limited to just that function, it will be visible to any code following the function definition).
You can use enumeration constants for integer values:
enum { FOO = 1, BAR = 10, BLETCH = 100 };
These are not replaced after preprocessing, so they're visible in debuggers. Values are known at compile time, so they can be used for array sizes or cases in switch
statements. Enumeration constants occupy the same name space as variable and function names, so you can't use the same symbol for an enumeration constant and a variable. Enumeration constants do obey scoping rules; if you define the enum
type within a function, those enumeration constants will not be visible outside of the function body.
You cannot use enumeration constants for non-int
values (strings, floats, any integer value wider than int
).
You can use const
-qualified variables:
const double PI = 3.14159265359;
const char * const STR = "This is a string constant";
const int FOO = 10;
Almost as flexible as preprocessor macros, symbols aren't replaced by the preprocessor. Like enumeration constants, variables obey scoping rules. Downside is that storage must be allocated for all these objects at runtime, and they don't count as compile-time constants, meaning they can't be used for things like cases in a switch
statement.
No one scheme is always "best"; it really depends on what you need.
For my part, I use the enum
method for related integer constants (error codes, machine states, etc.), and const
-qualified variables for just about everything else. I rarely use preprocessor macros for symbolic constants.
Upvotes: 3