Is enum a suitable way to implement a "local define?"

P

partremmaps

Of course I could use malloc and all that but this isn't about that.

Often I do like the following:

int i
#define sizeMAX 1024
static char buffer[sizeMAX];
i=0;
while(i<sizeMAX)
{
putc(buffer);
}
.... lots more code that reference buffer[] and sizeMAX ...
#undef sizeMAX


But this seems messy because I could forget the #undef and then that #define is left active for anything following in the code.

I tried const int sizeMAX=1024 but of course the declaration of buffer doesn't allow that as an array size specifier.

However, doing "enum { sizeMAX=1024 };" seems to work, but I can't tell from a quick word search in the standard whether it is supposed to always work.

Obviously enum was meant to map multiple words to a list of ints, and if the standard allows that list to be set up at run time then it may not work in some standard implementations.

Logically, "const int x=5" would be of the same functionality as "enum {x=5}" however GCC treats them differently, allowing the enum'ed x to be used as the array size specifier while not allowing the const int to be used as such.

Thanks,

Jesse
 
S

Stefan Ram

I tried const int sizeMAX=1024 but of course the declaration
of buffer doesn't allow that as an array size specifier.

I think C11 allows this, see: N1570 6.7.6.2 Array declarators.
However, doing "enum { sizeMAX=1024 };" seems to work, but I
can't tell from a quick word search in the standard whether
it is supposed to always work.

Since you do not seem to refer to the uncancelled and
unreplaced standard, you might refere to some of the
standards that now are cancelled and replaced. So which
standard do you refer to with »the standard«?

The size of an array that has not a variable lenght array
type needs to be given as an integer constant expression.
An enumeration constant is an integer constant expression
while a variable of a const-qualified type is not.
 
S

Stefan Ram

I think C11 allows this, see: N1570 6.7.6.2 Array declarators.
Since you do not seem to refer to the uncancelled and

I have failed to take into account that your array is static!

In this case, I believe, it cannot be a variable-length array.

So, an enum actually should be fine.
 
K

Keith Thompson

I think C11 allows this, see: N1570 6.7.6.2 Array declarators.

C90 does not have variable-length arrays.

C99 does, but permits them only with automatic storage duration;
you can't define a VLA at file scope or with the "static" keyword.

C11 made VLA support, along with several other language features,
optional. I'm skeptical that any implementers of C11 compilers will
take advantage of that permission, but we'll see how it plays out.
 
K

Keith Thompson

Of course I could use malloc and all that but this isn't about that.

Often I do like the following:

int i
#define sizeMAX 1024
static char buffer[sizeMAX];
i=0;
while(i<sizeMAX)
{
putc(buffer);
}
... lots more code that reference buffer[] and sizeMAX ...
#undef sizeMAX


But this seems messy because I could forget the #undef and then that
#define is left active for anything following in the code.

I tried const int sizeMAX=1024 but of course the declaration of buffer
doesn't allow that as an array size specifier.

However, doing "enum { sizeMAX=1024 };" seems to work, but I can't
tell from a quick word search in the standard whether it is supposed
to always work.

Obviously enum was meant to map multiple words to a list of ints, and
if the standard allows that list to be set up at run time then it may
not work in some standard implementations.

Logically, "const int x=5" would be of the same functionality as "enum
{x=5}" however GCC treats them differently, allowing the enum'ed x to
be used as the array size specifier while not allowing the const int
to be used as such.


It's not just GCC; that behavior is specified by the C standard. Given
`const int x = 5;`, the expression `x` is not a constant expression, and
cannot be used in any context that requires one.

If you use a macro, the convention is to write the name in all-caps:

#define SIZEMAX 1024
static char buffer[SIZEMAX];

This serves as a reminder to the reader that SIZEMAX is a macro, which
is useful since macro names behave quite differently from other
identifiers.

Most programmers don't bother to remove the macro using #undef. If you
choose the name carefully, there's usually no real need to do so.

In this case, without the "#undef", both "SIZEMAX" and "buffer" are
visible from the point where they're defined to the end of the
translation unit, which seems like the behavior you'd want.

As for using an "enum", that's perfectly valid as well. As you point
out, enums aren't really intended for this kind of thing, but the
language rules defining them permit this usage, and they aren't going to
change.

This declaration:

enum { sizeMAX = 1024 };

defines two things: an anonymous enumeration type (which is compatible
with some implementation-defined integer type), and a constant of type
int called sizeMAX. You can freely use `sizeMAX` as a constant
expression; it's equivalent to the expression `1024`.

One drawback is that you can't use this mechanism to define a constant
of a type other than int, but that's probably not a problem in this
case.

It's admittedly odd that enumeration constants are of type int rather
than of the enumerated type. It's for historical reasons.

(C++ has different rules, BTW, but that needn't concern you unless your
code is intended to be used both as C and as C++.)

Incidentally, when posting to Usenet, it's helpful to use hard line
breaks to keep your text down to less than 80 columns, preferably 72 or
so. Google Groups layers a web interface on top of the much older
Usenet text interface, and does a very poor job of it.
 
M

Malcolm McLean

Of course I could use malloc and all that but this isn't about that.

Often I do like the following:

int i
#define sizeMAX 1024
static char buffer[sizeMAX];
i=0;
while(i<sizeMAX)
{
putc(buffer);
}

... lots more code that reference buffer[] and sizeMAX ...

#undef sizeMAX

But this seems messy because I could forget the #undef and then that #define > is left active for anything following in the code.

Also if you do
#define SIZE_MAX 1024
....
#undef SIZE_MAX
....
#define SIZE_MAC 1000
....

You're creating a nightmare for any maintaing programmer.

In C, the natural unit is the source file. #defines should be treated as having
file scope, or being exported.
So either everything uses the same SIZE_MAX, or hardocde it. Beginners are
often taught that magic constants are bad in code. There's some truth in that,
but dependencies are worse. And if you're declaring a buffer, you need to
understand that the function has a limit on the size of input it can handle,
it doesn't vanish by putting a layer of in between the constant and the source.

If 1024 becomes a problem, you'll need to go through the whole function very
carefully to see what restrictions on N you have anyway, you might need to
move to malloc() or put in assertion checks. It's rarely a case of editing
the value without really looking at the code.
 
B

BartC

Often I do like the following:
#define sizeMAX 1024
But this seems messy because I could forget the #undef and then that
#define is left active for anything following in the code.

I tried const int sizeMAX=1024 but of course the declaration of buffer
doesn't allow that as an array size specifier.

However, doing "enum { sizeMAX=1024 };" seems to work, but I can't tell
from a quick word search in the standard whether it is supposed to always
work.

Obviously enum was meant to map multiple words to a list of ints, and if
the standard allows that list to be set up at run time then it may not
work in some standard implementations.

Logically, "const int x=5" would be of the same functionality as "enum
{x=5}" however GCC treats them differently, allowing the enum'ed x to be
used as the array size specifier while not allowing the const int to be
used as such.

It is strange but C doesn't have what I call /named constants/, which are
names applied to compile-time expressions.

The nearest you will get is with the enum{} feature as you've used. Those
names have the scope rules you expect, but it will only work for int types,
which is not a problem for your intended use. It just seems odd to have to
define:

enum {sizeMAX = 1024};

instead of, for example:

constant sizeMAX = 1024;

(Syntax such as 'const int' is a source of endless confusion for people not
that familiar with C. The 'const' there means readonly. But I avoid it to
reduce clutter and even more compiler type errors than I usually get; and in
a complex type spec I can never figure out which part the const applies to
anyway.)
 
I

Ike Naar

Often I do like the following:

int i
#define sizeMAX 1024
static char buffer[sizeMAX];
i=0;
while(i<sizeMAX)
{
putc(buffer);


(don't forget to increment i in the loop body!)
}
... lots more code that reference buffer[] and sizeMAX ...
#undef sizeMAX

But this seems messy because I could forget the #undef and then that
#define is left active for anything following in the code.

I tried const int sizeMAX=1024 but of course the declaration of buffer
doesn't allow that as an array size specifier.

However, doing "enum { sizeMAX=1024 };" seems to work, but I can't
tell from a quick word search in the standard whether it is supposed
to always work.

The enum method will work.

Sometimes it might be an option to forget about named constants,
and use sizeof:

static char buffer[1024];
for (int i = 0; i < sizeof buffer / sizeof buffer[0]; ++i)
{
do_something(buffer);
}
/* ... */
static double otherbuffer[33];
for (int i = 0; i < sizeof otherbuffer / sizeof otherbuffer[0]; ++i)
{
do_something_else(otherbuffer);
}

or, using a #define to capture the sizeof expression:

#define NUMBER_OF_ELEMENTS(array) (sizeof (array) / sizeof (array[0]))

static char buffer[1024];
for (int i = 0; i < NUMBER_OF_ELEMENTS(buffer); ++i)
{
do_something(buffer);
}
/* ... */
static double otherbuffer[33];
for (int i = 0; i < NUMBER_OF_ELEMENTS(otherbuffer); ++i)
{
do_something_else(otherbuffer);
}
 
J

jacob navia

Le 05/04/2014 22:07, (e-mail address removed) a écrit :
I tried const int sizeMAX=1024 but of course the declaration of buffer doesn't allow that as an array size specifier.

The lcc-win compiler will accept that if you declare sizeMax as static.
 
D

David Brown

As for using an "enum", that's perfectly valid as well. As you point
out, enums aren't really intended for this kind of thing, but the
language rules defining them permit this usage, and they aren't going to
change.

This declaration:

enum { sizeMAX = 1024 };

defines two things: an anonymous enumeration type (which is compatible
with some implementation-defined integer type), and a constant of type
int called sizeMAX. You can freely use `sizeMAX` as a constant
expression; it's equivalent to the expression `1024`.

One drawback is that you can't use this mechanism to define a constant
of a type other than int, but that's probably not a problem in this
case.

Can't you get an unsigned int constant with

enum { sizeMax = 1024u };

and long and unsigned longs using "l" and "ul" suffixes?
 
D

David Brown

Often I do like the following:
#define sizeMAX 1024
But this seems messy because I could forget the #undef and then that
#define is left active for anything following in the code.

I tried const int sizeMAX=1024 but of course the declaration of buffer
doesn't allow that as an array size specifier.

However, doing "enum { sizeMAX=1024 };" seems to work, but I can't tell
from a quick word search in the standard whether it is supposed to always
work.

Obviously enum was meant to map multiple words to a list of ints, and if
the standard allows that list to be set up at run time then it may not
work in some standard implementations.

Logically, "const int x=5" would be of the same functionality as "enum
{x=5}" however GCC treats them differently, allowing the enum'ed x to be
used as the array size specifier while not allowing the const int to be
used as such.

It is strange but C doesn't have what I call /named constants/, which are
names applied to compile-time expressions.

The nearest you will get is with the enum{} feature as you've used. Those
names have the scope rules you expect, but it will only work for int types,
which is not a problem for your intended use. It just seems odd to have to
define:

enum {sizeMAX = 1024};

instead of, for example:

constant sizeMAX = 1024;

(Syntax such as 'const int' is a source of endless confusion for people not
that familiar with C. The 'const' there means readonly. But I avoid it to
reduce clutter and even more compiler type errors than I usually get;
and in
a complex type spec I can never figure out which part the const applies to
anyway.)
[/QUOTE]

There is an easy solution to confusion about complex type specs - use
typedef's to split it up so that every type is completely obvious. Step
by step, no more than two or three parts per type, and you can't go
wrong. And just as importantly, anyone having even a quick glance at
your code can't go wrong either.

For the most part, "static const int sizeMax = 1024;" does the same job
as "enum { sizeMax = 1024 };" or "#define sizeMax 1024", but it does so
with safer typing, better static error checking, more flexibility and -
IMHO - clearer code. The only exception is that you can't use the
"static const" for the size of statically allocated arrays. It's a
painful omission from the standards.

Of course, it is possible to write things in reverse:

static char buffer[1024];
static const int sizeMax = sizeof(buffer) / sizeof(buffer[0]);

Whether or not you think that is better is a matter of opinion, but it's
an alternative that avoids the #define or the somewhat unnatural enum,
and still avoids using the "magic number" twice in the code.
 
K

Keith Thompson

David Brown said:
Can't you get an unsigned int constant with

enum { sizeMax = 1024u };

and long and unsigned longs using "l" and "ul" suffixes?

No. 1024u is of type unsigned int, but sizeMax is still of type int.

For example, this:

enum { too_big = UINT_MAX };

is invalid (unless UINT_MAX == INT_MAX, which is possible but odd).

N1570 6.7.2.2p2:

Constraints

The expression that defines the value of an enumeration constant
shall be an integer constant expression that has a value
representable as an int.

The expression doesn't have to be of type int, but it has to be within
the range of int.
 
J

James Kuyper

On 05/04/14 23:14, Keith Thompson wrote: ....

Can't you get an unsigned int constant with

enum { sizeMax = 1024u };

and long and unsigned longs using "l" and "ul" suffixes?

"An identifier declared as an enumeration constant has type int."
(6.4.4.3p2).

"The expression that defines the value of an enumeration constant shall
be an integer constant expression that has a value representable as an
int." (6.7.2.2p2)
 
I

Ian Collins

David said:
For the most part, "static const int sizeMax = 1024;" does the same job
as "enum { sizeMax = 1024 };" or "#define sizeMax 1024", but it does so
with safer typing, better static error checking, more flexibility and -
IMHO - clearer code. The only exception is that you can't use the
"static const" for the size of statically allocated arrays. It's a
painful omission from the standards.

Of course, it is possible to write things in reverse:

static char buffer[1024];
static const int sizeMax = sizeof(buffer) / sizeof(buffer[0]);

Whether or not you think that is better is a matter of opinion, but it's
an alternative that avoids the #define or the somewhat unnatural enum,
and still avoids using the "magic number" twice in the code.

Or if you want the constant without the buffer:

typedef char Buffer[1024];
const size_t sizeMax = sizeof(Buffer);
 
I

Ian Collins

David said:
Can't you get an unsigned int constant with

enum { sizeMax = 1024u };

and long and unsigned longs using "l" and "ul" suffixes?

Are you thinking of the improved enums in C++ here?
 
D

David Brown

Are you thinking of the improved enums in C++ here?

That could be it - would sizeMax be an unsigned int in C++? (I believe
that in C++, enums can be of different sizes, but I have not had
occasion or need to learn the rules.)
 
I

Ian Collins

David said:
That could be it - would sizeMax be an unsigned int in C++? (I believe
that in C++, enums can be of different sizes, but I have not had
occasion or need to learn the rules.)

In C++ you could write

enum : unsigned { sizeMax = 1024u };
 
B

BartC

David Brown said:
On 05/04/14 23:39, BartC wrote:

There is an easy solution to confusion about complex type specs - use
typedef's to split it up so that every type is completely obvious.

Sorry, but anything that involves doing X, Y or Z to make type specs 'easy'
isn't a solution! It shouldn't be necessary to do anything; they should be
self-explanatory. However if you are stuck with writing actual C (I'm not)
then I suppose you might need to use these methods.

(But I would probably still never use 'const' anyway.)
For the most part, "static const int sizeMax = 1024;" does the same job as
"enum { sizeMax = 1024 };" or "#define sizeMax 1024", but it does so with
safer typing, better static error checking, more flexibility and - IMHO -
clearer code. The only exception is that you can't use the "static const"
for the size of statically allocated arrays. It's a painful omission from
the standards.
Of course, it is possible to write things in reverse:

static char buffer[1024];
static const int sizeMax = sizeof(buffer) / sizeof(buffer[0])
Whether or not you think that is better is a matter of opinion, but it's
an alternative that avoids the #define or the somewhat unnatural enum, and
still avoids using the "magic number" twice in the code.

But, sizeMax is still, as far as I can gather, some value with reserved
storage, that you can take the address of. And you can't declare another
array using the same size as you say.

So it still falls short of what you can do with a proper named constant.

You're right that it's another thing that would have been very easy to get
right, but forty years on and the language still doesn't have a plain,
straightforward way of declaring a named constant!

(It's a little crazy really; I have now several language projects where I
translate source code that has 'proper' named constants, into actual C. Did
I use #defines, or enums? Both have limitations to do with scope and type.
But I've just checked and the solution I came up with was the following; if
the source uses this (made C-like so as not to frighten anyone):

const sizeMax = 1024 /* 'int' is optional */
char buffer[sizeMax]
int i=sizeMax

The generated C is just this:

char buffer[1024];
int i=1024;

the problem simply disappears! It's almost a non-issue, unless you have
to write actual C.)
 
J

James Kuyper

On 04/06/2014 05:30 PM, David Brown wrote:
....
That could be it - would sizeMax be an unsigned int in C++? (I believe
that in C++, enums can be of different sizes, but I have not had
occasion or need to learn the rules.)

The sizes of enumerated types can vary in C, too; it's only enumeration
constants that are of type 'int'. That means that there's not much point
is making an enumerated type be bigger than an int, but it could
usefully be smaller.
 
K

Keith Thompson

David Brown said:
There is an easy solution to confusion about complex type specs - use
typedef's to split it up so that every type is completely obvious. Step
by step, no more than two or three parts per type, and you can't go
wrong. And just as importantly, anyone having even a quick glance at
your code can't go wrong either.

For the most part, "static const int sizeMax = 1024;" does the same job
as "enum { sizeMax = 1024 };" or "#define sizeMax 1024", but it does so
with safer typing, better static error checking, more flexibility and -
IMHO - clearer code. The only exception is that you can't use the
"static const" for the size of statically allocated arrays. It's a
painful omission from the standards.

That's not the only exception. Given the "static const int" declaration
sizeMax is not a constant expression, and there are a number of contexts
in which it can't be used (in a case label, for example).

I don't know that I'd call it a "painful omission", but I agree that it
would be nice to have a way to define name constants. Copying C++'s
semantics would probably be a decent approach.
Of course, it is possible to write things in reverse:

static char buffer[1024];
static const int sizeMax = sizeof(buffer) / sizeof(buffer[0]);

Whether or not you think that is better is a matter of opinion, but it's
an alternative that avoids the #define or the somewhat unnatural enum,
and still avoids using the "magic number" twice in the code.

One problem with that is that to doesn't give a name to the value 1024.
For example, you might want two or more buffers with the same size.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top