Macro, enumeration, or const variable?

0 views
Skip to first unread message

Ming Hua

unread,
Apr 4, 2003, 4:26:41 PM4/4/03
to
Hi,

I can't make a decision choosing from #define'd macros, enumerations and
extern const variables in my program.

I need some constants, diffrent kinds of. To my knowledge there are
three ways to do them, so I can put everything in a header file, say
constant.h, and include it whenever I need them. The problem is, each
way has its own advantages and disadvantages.

I know the following issues:

1. Type checking. enum's and const variables make the compiler check
the type, while macros usually get around type checking.

2. Information for debugger. enum's and const's can have their names
kept in the object file, so debugger can use them.

3. Constant length arrays. const's can't be used to define an array of
constant length (at least not in C89).

So for floating point constants (like PI), I chose const, since enum's
are for integers only. I also want to use some flags in a integer,
with each bit indicating an option, like

<CODE>
if (flag | OPTION_A) {
/* deal with option A stuff */
}

/* ... */

flag = 0;
switch (choice) {
case 'A': flag |= OPTION_A;
break;
case 'B': flag |= OPTION_B;
break;
/* ... */
case '*': flag = OPTION_ALL; /* OPTION_ALL == OPTION_A | OPTION_B | ... */
break;
}
</CODE>

while flag is actually a integer, and OPTION_A has a single bit set,
like 0x0001, 0x0010, etc. I think I can choose either enum or const
here. I heard somewhere that enum's usually shouldn't be used with
bitwise operators, is that true? (and if yes, what is the reason?) So I
suppose I should use const's here. Then the thing I dislike is that all
flags looks the same type (say, unsigned int). So maybe I should
typedef them, like

<CODE>
typedef unsigned int fileflag_t;
typedef unsigned int dataflag_t;
</CODE>

to explictly show they are diffrent flags. But again, in a thread
several days ago many people suggested not to mask type with typedef's
except for ADTs. So...

I read the FAQ and found some discussion about enum's and macros, but
few of them mentioned const variables. So I am asking for some advice.
Is my understanding correct, and is there anything I'm not aware of?
And I am also wondering (just curious), is there any case we must use
macros, besides for the size of constant length arrays? And, why few
people mention const's as an option for constant integers?

Thanks in advance.

Ming
2003.04.04


Jan Engelhardt

unread,
Apr 4, 2003, 4:55:23 PM4/4/03
to
>Hi,
>
>I can't make a decision choosing from #define'd macros, enumerations and
>extern const variables in my program.

For function substituions, I usually use #defines ;) like
#if DEBUG
# define do_this(...) this(); that();
#else
# define do_this(...) only this();
#endif

>I know the following issues:

[...]
>
>1. Type checking
>2. Information for debugger
>3. Constant length arrays
>
>So for floating point constants (like PI), [...]

"Running numbers" (like errno.h has), I do stuff into an enum,
anything else into variables, and [fancy] substituions as #defines.

><CODE>
>if (flag | OPTION_A) {
> /* deal with option A stuff */
>}

[...]

OPTION_* is candidate for enum. For me.

>I read the FAQ and found some discussion about enum's and macros, but
>few of them mentioned const variables. So I am asking for some advice.
>Is my understanding correct, and is there anything I'm not aware of?
>And I am also wondering (just curious), is there any case we must use
>macros, besides for the size of constant length arrays? And, why few
>people mention const's as an option for constant integers?

From the deepest point (ASM) I think that using a variable takes
up space in memory/stack, whereas a #defined constant (gets "replaced"
in source code) may gets stuffed into the executable code and nowhere
else (at least true for integers).

--
Example C/ASM:
#define CONSTANT 5 // or enum
a += CONSTANT;
gets
(mov %eax = a)
add %eax,5
whereas CONSTANT as a variable *might* (depends on optimization)
-- in the worst case if you request -- do it as a var:
int con = 5;
a += con;
gets
mov %eax=a
mov %ebx=con
add %eax,%ebx
mov a=%eax

- Jan Engelhardt

Mark McIntyre

unread,
Apr 4, 2003, 5:30:02 PM4/4/03
to
On 4 Apr 2003 21:26:41 GMT, in comp.lang.c , min...@riREMOVEce.edu
(Ming Hua) wrote:

>Hi,
>
>I can't make a decision choosing from #define'd macros, enumerations and
>extern const variables in my program.

Well, firstly const variables are not constants. So if you want
something constant, don't use them. Apart from that you've listed most
of the pros and cons. My own view is:

If you have a constant, use a macro.
#define PI 3.1415
#define ARRAYSIZE 234
etc

If you want a variable that you can't change in a function, use const
int dosomething(const int x) // x can't be changed by the function

if you want an enumerated list of things, use an enum:
list of colours
list of counties
etc

>So for floating point constants (like PI), I chose const, since enum's
>are for integers only.

For this, I'd use a macro.

> I also want to use some flags in a integer,
>with each bit indicating an option, like
>
><CODE>
>if (flag | OPTION_A) {

macro

>while flag is actually a integer, and OPTION_A has a single bit set,
>like 0x0001, 0x0010, etc. I think I can choose either enum or const
>here.

why?

>I heard somewhere that enum's usually shouldn't be used with
>bitwise operators, is that true?

never heard that.

>I read the FAQ and found some discussion about enum's and macros, but
>few of them mentioned const variables.

Probably because they've not much use in C, except to protect function
arguments.

>macros, besides for the size of constant length arrays? And, why few
>people mention const's as an option for constant integers?

because they're not constant

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.angelfire.com/ms3/bchambless0/welcome_to_clc.html>

Karthik Gurusamy

unread,
Apr 4, 2003, 9:58:57 PM4/4/03
to
min...@riREMOVEce.edu (Ming Hua) wrote in message news:<b6ktah$6vk$1...@joe.rice.edu>...

I also want to use some flags in a integer,
> with each bit indicating an option, like
>
> <CODE>
> if (flag | OPTION_A) {
> /* deal with option A stuff */
> }
>
> /* ... */
>
> flag = 0;
> switch (choice) {
> case 'A': flag |= OPTION_A;
> break;
> case 'B': flag |= OPTION_B;
> break;
> /* ... */
> case '*': flag = OPTION_ALL; /* OPTION_ALL == OPTION_A | OPTION_B | ... */
> break;
> }
> </CODE>
>
> while flag is actually a integer, and OPTION_A has a single bit set,
> like 0x0001, 0x0010, etc. I think I can choose either enum or const
> here. I heard somewhere that enum's usually shouldn't be used with
> bitwise operators, is that true? (and if yes, what is the reason?) So I
> suppose I should use const's here. Then the thing I dislike is that all
> flags looks the same type (say, unsigned int). So maybe I should
> typedef them, like

For these kind of flags, I find using bit fields convenient. The messy
work of ORs and ANDs is done by the compiler.
typedef struct {
uint is_option_A :1 ;
uint is_option_B :1 ;
...etc...
} foo_option_flags;

Now we leave the optimization responsibility with the compiler and
the code is more readable using direct writing/reading 1/0 into the
variables.

Karthik

Ming Hua

unread,
Apr 5, 2003, 6:11:20 PM4/5/03
to
On Fri, 04 Apr 2003 23:30:02 +0100, Mark McIntyre
<markmc...@spamcop.net> wrote:
>Well, firstly const variables are not constants. So if you want
>something constant, don't use them.

Why do you say they are not constants? Do you mean that they can be
modified anyway (e.g., by casting pointers)?

>Apart from that you've listed most
>of the pros and cons. My own view is:
>
>If you have a constant, use a macro.
>#define PI 3.1415
>#define ARRAYSIZE 234
>etc
>
>If you want a variable that you can't change in a function, use const
> int dosomething(const int x) // x can't be changed by the function

I think you mean: int dosomething(const int *x), don't you? Since
(int x) is called by value.

[snipped]


>>So for floating point constants (like PI), I chose const, since enum's
>>are for integers only.
>
>For this, I'd use a macro.
>
>> I also want to use some flags in a integer,
>>with each bit indicating an option, like
>>
>><CODE>
>>if (flag | OPTION_A) {
>
>macro
>
>>while flag is actually a integer, and OPTION_A has a single bit set,
>>like 0x0001, 0x0010, etc. I think I can choose either enum or const
>>here.
>
>why?

Because I like type checking and debugger information very much.
Especially the latter -- in a scientific computation program full of
numbers, it would help a lot if you can see the name instead of value
when debugging.

[snipped]


>>macros, besides for the size of constant length arrays? And, why few
>>people mention const's as an option for constant integers?
>
>because they're not constant

Would you please explain a little more?

Thanks,
Ming
2003.04.05

--
For Email, send to minghua at rice dot edu

Mark McIntyre

unread,
Apr 5, 2003, 7:13:40 PM4/5/03
to
On Sat, 5 Apr 2003 23:11:20 +0000 (UTC), in comp.lang.c ,
min...@riREMOVEce.edu (Ming Hua) wrote:

>On Fri, 04 Apr 2003 23:30:02 +0100, Mark McIntyre
><markmc...@spamcop.net> wrote:
>>Well, firstly const variables are not constants. So if you want
>>something constant, don't use them.
>
>Why do you say they are not constants? Do you mean that they can be
>modified anyway (e.g., by casting pointers)?

Yes, and though thats undefined behaviour, many compilers allow it.

The main point is, a const variable is a variable whose value can't be
changed, but its still a variable. and you can cast away the
constness. The standard also seems to imply that you can modify a
const object using another const object.

>>If you want a variable that you can't change in a function, use const
>> int dosomething(const int x) // x can't be changed by the function
>
>I think you mean: int dosomething(const int *x), don't you? Since
>(int x) is called by value.

yes. missing asterisk.

>>>while flag is actually a integer, and OPTION_A has a single bit set,
>>>like 0x0001, 0x0010, etc. I think I can choose either enum or const
>>>here.
>>
>>why?
>
>Because I like type checking and debugger information very much.

Debugger info - use a better debugger (MSVC shows you the name of hte
macro).
Type checking - you get no benefit from that because C's typechecking
is so weak.

David Thompson

unread,
Apr 9, 2003, 1:59:25 AM4/9/03
to
Ming Hua <min...@riREMOVEce.edu> wrote :

> I can't make a decision choosing from #define'd macros, enumerations and
> extern const variables in my program.
[snip]

> I know the following issues:
>
> 1. Type checking. enum's and const variables make the compiler check
> the type, while macros usually get around type checking.
>
enumerated values, and const variables used for their values,
are not checked any more or less than literal values either
produced from a macro or written out. Where the default
argument promotions apply (varargs or a nonprototyped
function call) enumerated values are always type int,
and const variables or literals are *at least* int or double
but may be defined/suffixed as wider.
(Note however that variables, including const variables,
of an enum _type_ may be compatible with any suitable
integer type, not necessarily plain signed int. Although
it is silly and wasteful to make them larger than int.)

Pointers to all variables, const or not, are strictly typed,
but you can't even *have* a pointer to an enum value or
literal, so that's not comparable.

1'. Const variables probably occupy actual memory,
and may be compiled as an actual access -- although
the implementation can always optimize away the access
if the/a definition is available (since changing a const object
is UB) and can optimize away the object if it can determine
the address is never taken or at least never used or compared.
Enum and literal macro values are typically compiled inline,
which for 'normal' architectures is slightly faster.

1''. Although not officially required, in practice if you *define*
a global variable as nonconst with a value (or even set it in
code using the nonconst declaration or by casting away const)
but *declare* it elsewhere as const, you get a 'run time parameter';
you can change it with the 'privileged' code or the debugger, and
have all the other code use the changed value while being unable
to change it without casting, without recompiling.

> 2. Information for debugger. enum's and const's can have their names
> kept in the object file, so debugger can use them.
>

Depending on the implementation. It is possible, but
AFAIK rarer, to have #define's in debugging info (by
integrating the preprocessor and compiler, as is legal).

> 3. Constant length arrays. const's can't be used to define an array of
> constant length (at least not in C89).
>

(Although it can in C++, but that's offtopic.)

4. Names of value-like macros cannot be used for *anything*
else: not as struct/union field names, not as enum names,
not as struct/union/enum tags, not as function names, not
as local variables (or parameters). (global) enum and const
variable names can be reused as fields, tags, and local variables.

This is the main reason for the convention that value-like
macro names are ALL CAPS, so they don't conflict with
the names used for other identifiers.

> So for floating point constants (like PI), I chose const, since enum's
> are for integers only. I also want to use some flags in a integer,

> with each bit indicating an option, [snip]
>
Also enums cannot be integer values that are, or may be, outside
the range of (signed) int. (In C++ they can go up to unsigned long.)

> like 0x0001, 0x0010, etc. I think I can choose either enum or const
> here. I heard somewhere that enum's usually shouldn't be used with
> bitwise operators, is that true? (and if yes, what is the reason?) So I
> suppose I should use const's here. Then the thing I dislike is that all
> flags looks the same type (say, unsigned int). So maybe I should

> typedef them, like [snip]

Some bitwise operations should be done on unsigned types,
and to avoid thinking about each case it may be preferred
to do all of them that way, and enums are signed int; but
that is fine *if* you don't need the sign bit of int, or any bits
beyond int (long, long long or perhaps extended types in C99).

> to explictly show they are diffrent flags. But again, in a thread
> several days ago many people suggested not to mask type with typedef's
> except for ADTs. So...
>

Could just use a comment -- it has the same effect as a
typedef to a simple type, except perhaps for debugging info.

> I read the FAQ and found some discussion about enum's and macros, but
> few of them mentioned const variables. So I am asking for some advice.
> Is my understanding correct, and is there anything I'm not aware of?
> And I am also wondering (just curious), is there any case we must use
> macros, besides for the size of constant length arrays? And, why few
> people mention const's as an option for constant integers?
>

You can use an enumerated value for an array size, as long
as it's in the range of int, but that's portably only up to 32767.

Because they're not needed; macros and/or enums work fine,
and are typically (slightly) more efficient.

--
- David.Thompson 1 now at worldnet.att.net

E. Robert Tisdale

unread,
Apr 9, 2003, 4:06:24 PM4/9/03
to
Ming Hua wrote:
>
> I can't make a decision choosing from #define'd macros,
> enumerations and extern const variables in my program.

const variable is an oxymoron.
You probably mean constants or const values.
>
> I need some different kinds of constants.
> To my knowledge, there are three ways to do them
> so that I can put everything in a header file, say constant.h,
> and include it whenever I need them. The problem is that


> each way has its own advantages and disadvantages.
>
> I know the following issues:
>
> 1. Type checking. enum's and const variables make the compiler check
> the type, while macros usually get around type checking.
>
> 2. Information for debugger. enum's and const's can have their names
> kept in the object file, so debugger can use them.
>
> 3. Constant length arrays. const's can't be used
> to define an array of constant length (at least not in C89).

So use a c99 compiler instead.

> So for floating point constants (like PI),
> I chose const, since enum's are for integers only.
> I also want to use some flags in a integer,
> with each bit indicating an option, like
>
> <CODE>
> if (flag | OPTION_A) {
> /* deal with option A stuff */
> }
>
> /* ... */
>
> flag = 0;
> switch (choice) {
> case 'A': flag |= OPTION_A;
> break;
> case 'B': flag |= OPTION_B;
> break;
> /* ... */
> case '*': flag = OPTION_ALL; /* OPTION_ALL == OPTION_A | OPTION_B | ... */
> break;
> }
> </CODE>
>
> while flag is actually a integer, and OPTION_A has a single bit set,
> like 0x0001, 0x0010, etc. I think I can choose either enum or const
> here. I heard somewhere that enum's usually shouldn't be used with
> bitwise operators, is that true? (and if yes, what is the reason?)
> So I suppose I should use const's here. Then the thing I dislike

> is that all flags look like the same type (say, unsigned int).


> So maybe I should typedef them, like
>
> <CODE>
> typedef unsigned int fileflag_t;
> typedef unsigned int dataflag_t;
> </CODE>
>

> to explicitly show they are different flags. But again, in a thread


> several days ago many people suggested not to mask type with typedef's
> except for ADTs. So...
>
> I read the FAQ and found some discussion about enum's and macros, but
> few of them mentioned const variables. So I am asking for some advice.

> Is my understanding correct? And is there anything I'm not aware of?


> And I am also wondering (just curious),

> is there any case where we must use macros,


> besides for the size of constant length arrays?
> And, why few people mention const's
> as an option for constant integers?

The const qualifier is relatively new
to the C computer programming language.
It should eventually replace all C preprocessor macros
that represent literal constants.
Use the static qualifier along with the const qualifier
for global constants that you need to define in header files.

C preprocessor macros are still required
for "conditional compilation" --

#ifdef myMacro
/* compile this overriding code */
#else
/* compile this default code */
#endif

and can still be useful for defining constants
with compile time options

$ cat main.c
int main(int argc, char* argv[]) {
const int i = I;
return 0;
}

$ gcc -DI=33 -o main main.c

Kevin Easton

unread,
Apr 9, 2003, 10:33:00 PM4/9/03
to
E. Robert Tisdale <E.Robert...@jpl.nasa.gov> wrote:
> Ming Hua wrote:
>>
>> I can't make a decision choosing from #define'd macros,
>> enumerations and extern const variables in my program.
[snip]

> The const qualifier is relatively new
> to the C computer programming language.
> It should eventually replace all C preprocessor macros
> that represent literal constants.
> Use the static qualifier along with the const qualifier
> for global constants that you need to define in header files.

That will only be possible when the language has changed so that this
works:

static const int START_NUMBER = 10;
int i = START_NUMBER;

at file scope.

- Kevin.

CBFalconer

unread,
Apr 9, 2003, 11:03:27 PM4/9/03
to
"E. Robert Tisdale" wrote:
>
... snip ...

>
> The const qualifier is relatively new
> to the C computer programming language.
> It should eventually replace all C preprocessor macros
> that represent literal constants.
> Use the static qualifier along with the const qualifier
> for global constants that you need to define in header files.

Utter nonsense. The const qualifier signifies that a variable
should not be altered. It DOES NOT create a compile time
constant.

#define VALUE 123
const int value = 123;

are much different things. VALUE can be used, for example, in:

char string[VALUE]; /* to create an array of 123 chars */

VALUE occupies no storage. value does. The address of value can
be taken.

--
Chuck F (cbfal...@yahoo.com) (cbfal...@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!


E. Robert Tisdale

unread,
Apr 9, 2003, 11:30:44 PM4/9/03
to
CBFalconer wrote:

> E. Robert Tisdale" wrote:
> [snip]


>>The const qualifier is relatively new
>>to the C computer programming language.
>>It should eventually replace all C preprocessor macros
>>that represent literal constants.
>>Use the static qualifier along with the const qualifier
>>for global constants that you need to define in header files.
>
> Utter nonsense.
> The const qualifier signifies that
> a variable should not be altered.
> It DOES NOT create a compile time constant.
>
> #define VALUE 123
> const int value = 123;
>
> are much different things. VALUE can be used, for example, in:
>
> char string[VALUE]; /* to create an array of 123 chars */
>
> VALUE occupies no storage. value does.
> The address of value can be taken.

You are confused.
The ANSI/ISO C standards carefully avoids
specifying any kind of data representation.
A good optimizing C compiler will emit the same code
for the above C preprocessor macro VALUE and const int value.
Unless there is a pointer to value that is actually used,
the C compiler may use the same (immediate) storage
for the value of const int value that it uses
for the C preprocessor macro VALUE.
The restriction for array declarations is a C89 anachronism.
The current C99 standard even allows array declarations
to use variable dimension specifiers.

Cling to your old habits if you must.
Programming is evolutionary and *not* revolutionary.
Young programmers who accept the new language features
will replace old programmers who can't or won't.

A scientific truth does not triumph
by convincing its opponents and making them see the light,
but rather because its opponents eventually die
and a new generation grows up that is familiar with it.
-- Max Planck


Kevin Easton

unread,
Apr 10, 2003, 12:34:18 AM4/10/03
to
E. Robert Tisdale <E.Robert...@jpl.nasa.gov> wrote:

I don't think VLAs can be defined at file scope, can they?

- Kevin.

CBFalconer

unread,
Apr 10, 2003, 5:24:57 AM4/10/03
to

I am not really worried if ERT is confused, I just don't want to
see any dewy eyed newbies led down the garden path by gross
misinformation.

Chris Torek

unread,
Apr 10, 2003, 10:48:12 AM4/10/03
to
In article <3E94E564...@jpl.nasa.gov>
E. Robert Tisdale <E.Robert...@jpl.nasa.gov> writes:
>You are confused.

You are fond of that phrase. Nonetheless, this time you are
clearly incorrect.

>The restriction for array declarations is a C89 anachronism.
>The current C99 standard even allows array declarations
>to use variable dimension specifiers.

Only inside functions, and even then, only if they have block scope.
The following (useless) function violates even the new C99 constraints:

void f(void) {
const int n = 100;
static char buf[n];
}

If you wish to argue that C89 and C99 both get the semantics of
"const" variables wrong, feel free to do so. I might even agree
with you; C++ certainly gets them "righter". But in C, "const
variables" really *are* variables, with most of the same semantics
as ordinary non-const variables, except for the restrictions on
changing their values.
--
In-Real-Life: Chris Torek, Wind River Systems (BSD engineering)
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W)
email: forget about it http://67.40.109.61/torek/ (for the moment)
Reading email is like searching for food in the garbage, thanks to spammers.

Jeremy Yallop

unread,
Apr 10, 2003, 12:26:38 PM4/10/03
to
Chris Torek wrote:
> In article <3E94E564...@jpl.nasa.gov>
> E. Robert Tisdale <E.Robert...@jpl.nasa.gov> writes:
>>The restriction for array declarations is a C89 anachronism.
>>The current C99 standard even allows array declarations
>>to use variable dimension specifiers.
>
> Only inside functions, and even then, only if they have block scope.

ITYM "only if they declare objects with automatic storage duration".

Jeremy.

Chris Torek

unread,
Apr 10, 2003, 12:48:29 PM4/10/03
to
>Chris Torek wrote:
>>[VLAs can occur] Only inside functions, and even then, only if
>>they have block scope.

In article <slrnb9b6gn...@saturn.cps.co.uk>,


Jeremy Yallop <jer...@jdyallop.freeserve.co.uk> wrote:
>ITYM "only if they declare objects with automatic storage duration".

Er, right. Not sure where my mind was when I wrote that. :-)

Dan Pop

unread,
Apr 10, 2003, 12:50:04 PM4/10/03
to

His example made it obvious that this is what he meant.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan...@ifh.de

those who know me have no need of my name

unread,
Apr 10, 2003, 3:29:27 PM4/10/03
to
in comp.lang.c i read:

>static const int START_NUMBER = 10;
>int i = START_NUMBER;
>
>at file scope.

fyi: for this trivial case there are enumeration constants, e.g.,

enum { START_NUMBER=10 };
int i = START_NUMBER;

--
bringing you boring signatures for 17 years

Kevin Easton

unread,
Apr 10, 2003, 9:19:41 PM4/10/03
to
those who know me have no need of my name <not-a-rea...@usa.net> wrote:
> in comp.lang.c i read:
>
>>static const int START_NUMBER = 10;
>>int i = START_NUMBER;
>>
>>at file scope.
>
> fyi: for this trivial case there are enumeration constants, e.g.,
>
> enum { START_NUMBER=10 };
> int i = START_NUMBER;

Certainly. But ERT was arguing that at some unspecified point in the
future, we'd be using const-qualified variables for all numeric
constants.

- Kevin.

E. Robert Tisdale

unread,
Apr 10, 2003, 9:26:35 PM4/10/03
to
Kevin Easton wrote:

> ERT was arguing that, at some unspecified point in the future,


> we'd be using const-qualified variables for all numeric constants.

No.

I'm arguing that the young programmers who *replace* you
will be using const-qualified variables for all numeric constants ;-)

Kevin Easton

unread,
Apr 10, 2003, 10:24:58 PM4/10/03
to
E. Robert Tisdale <E.Robert...@jpl.nasa.gov> wrote:

Geez, I'm only in my early 20s and I'm on the scrapheap already? It
certainly is a cruel world...

- Kevin.

Reply all
Reply to author
Forward
0 new messages