Enum question

B

Brian Dude

Hello, I have an enum that I'm using in my main source file and want to
extern it to another:

file1.c

enum START_PT
{
CENTER, UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
} pos;

int main(void)
{...}

/*--------------*/

file2.c

extern enum START_PT pos;

f()
{
switch(pos){
case CENTER:
break;
case UPPER_LEFT:
break;
/*etc...*/
}
}


I'm getting compilation errors for "undefined symbol CENTER" in file2.c.
Do the names in an enumeration not get carried over through extern?

TIA,
Brian Dude
 
S

Seebs

I'm getting compilation errors for "undefined symbol CENTER" in file2.c.
Do the names in an enumeration not get carried over through extern?

They do not. "extern" allows you to access *objects* -- but an enumerated
type is not an object. When file2 is compiled, nothing you've provided ever
tells the compiler what "CENTER" is. (The fact that, later, it might be
linked with something which knew doesn't matter; enumerations are dealt with
during compilation.)

The usual way to resolve this is to put the 'enum foo { a, b, c };' in
a header file, which is included from both modules.

-s
 
E

Eric Sosman

Hello, I have an enum that I'm using in my main source file and want to
extern it to another:

file1.c

enum START_PT
{
CENTER, UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
} pos;

int main(void)
{...}

/*--------------*/

file2.c

extern enum START_PT pos;

f()
{
switch(pos){
case CENTER:
break;
case UPPER_LEFT:
break;
/*etc...*/
}
}

I'm getting compilation errors for "undefined symbol CENTER" in file2.c.
Do the names in an enumeration not get carried over through extern?

They do not. Make yourself a header file, "startpt.h", say,
and put in it

enum START_PT
{
CENTER, UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
};

extern enum START_PT pos; /* or combine with the above */

This much says "There is a type called `enum START_PT', with constants
CENTER, UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, and LOWER_RIGHT having the
values 0 through 4. Also, there is a variable of this type named `pos';
it's not defined here, but some other file will define it eventually."

Now modify "file1.c" to read

#include "startpt.h"
enum START_PT pos; /* the "eventually" mentioned above */
int main(void) { ... }

and modify "file2.c" to read

#include "startpt.h"

.... without the `extern', because it's already in "startpt.h".

Why do things in this particular way? First, by putting the
declaration(s) in "startpt.h" you write them only once, and thus
remove any chance of accidentally writing them differently in
different files (imagine what would happen if two .c files disagreed
on the order of LOWER_LEFT and LOWER_RIGHT, one of them mistakenly
thinking it was a clockwise progression). Second, by including
the declarations in the same compilation as the definition (in this
case, "file1.h"), you give the compiler a chance to warn you if the
declarations and the definition disagree, perhaps having gotten out
of step while you were adding new features to the code.

By the way: You've only sketched your code and there's surely
more going on than is visible here, but on the surface this looks
like a poor use of a global variable. Globals are the right response
to some situations, but to fewer than many people at first think, and
they have a nasty way of causing trouble as a program evolves. At a
guess, you might be better off removing the `extern' and changing
the files to look like

/* file1.c */
#include "startpt.h"
static enum START_PT pos; /* `static' means "private" */
int main(void) {
/* or maybe put `pos' here, without `static' */
...
f(pos);
...
}

/* file2.c */
#include "startpt.h"
int f(enum START_PT pos) {
...
}

I'm not saying this *is* best for your circumstances, of which I know
too little, but that this is probably the pattern you should turn to
first, until some compelling reason makes you abandon it.
 
B

Brian Dude

Eric Sosman wrote:

They do not. Make yourself a header file, "startpt.h", say,
and put in it

enum START_PT
{
CENTER, UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, LOWER_RIGHT
};

extern enum START_PT pos; /* or combine with the above */

This much says "There is a type called `enum START_PT', with constants
CENTER, UPPER_LEFT, UPPER_RIGHT, LOWER_LEFT, and LOWER_RIGHT having the
values 0 through 4. Also, there is a variable of this type named `pos';
it's not defined here, but some other file will define it eventually."

Now modify "file1.c" to read

#include "startpt.h"
enum START_PT pos; /* the "eventually" mentioned above */
int main(void) { ... }

and modify "file2.c" to read

#include "startpt.h"

... without the `extern', because it's already in "startpt.h".

Why do things in this particular way? First, by putting the
declaration(s) in "startpt.h" you write them only once, and thus
remove any chance of accidentally writing them differently in
different files (imagine what would happen if two .c files disagreed
on the order of LOWER_LEFT and LOWER_RIGHT, one of them mistakenly
thinking it was a clockwise progression). Second, by including
the declarations in the same compilation as the definition (in this
case, "file1.h"), you give the compiler a chance to warn you if the
declarations and the definition disagree, perhaps having gotten out
of step while you were adding new features to the code.

By the way: You've only sketched your code and there's surely
more going on than is visible here, but on the surface this looks
like a poor use of a global variable. Globals are the right response
to some situations, but to fewer than many people at first think, and
they have a nasty way of causing trouble as a program evolves. At a
guess, you might be better off removing the `extern' and changing
the files to look like

/* file1.c */
#include "startpt.h"
static enum START_PT pos; /* `static' means "private" */
int main(void) {
/* or maybe put `pos' here, without `static' */
...
f(pos);
...
}

/* file2.c */
#include "startpt.h"
int f(enum START_PT pos) {
...
}

I'm not saying this *is* best for your circumstances, of which I know
too little, but that this is probably the pattern you should turn to
first, until some compelling reason makes you abandon it.

Good points. The only reason I'm doing things as such is because I just
recently decided to put a bunch of things into a separate file and
needed to quickly get that variable over. The idea of a header didn't
occur to me because that seemed a bit "grand" for just one variable, but
I will likely incorporate the idea as my project grows. Thanks!
 
D

David Thompson

They do not. "extern" allows you to access *objects* -- but an enumerated
type is not an object. <snip rest>

extern enables inter-t.u. access to objects and functions, but not ANY
type information, which as you noted is compile-time*: not enum types
or constants, not struct/union types, not typedefs. (* except C99 VLA,
and that has to be effectively 'auto' and so couldn't be sharable)

Also not macros, in case anyone is even more imaginatively wrong.
 

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

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top