External structs - newbie question

S

Simon

I'm having difficulty with a struct in two of my c files.

The header file for csd.c (the main program) contains the typedef for a
struct called tiles. There is only one struct in use (called "map")
throughout the time that the program is run, and as it's used by
virtually all of the functions it's currently a global. I realise that
this is probably bad practice but I'm still pretty far down the curve
when it comes to c.

The file org.c contains some code which alters certain of the values
within "map". I'd like to declare "map" in csd.c and then use extern
to tell org.c that it exists. Unfortunately, nothing that I do seems
to be able to achieve this. I'm definitely including the typedef in
both files, but if I put a statement like "extern map" in org.c and try
and compile it gives an error "subscripted value is neither array nor
pointer" when it gets to the line "map[j].terrain = 1;".

The only way that I can get the thing to compile is to have a header
file shared by both csd.c and org.c which contains the typedef followed
by the declaration of the global variable map. This makes me nervous
because as far as I can see the global "map" is being declared twice -
once by each of the files.

Any ideas?

Simon
 
R

Rachael

Is map an instance of the tiles struct, or a pointer to one? You can't
do map[j] if it's just a struct, which is probably what the compiler
message is complaining about.

For the extern declaration, you want
extern tiles map;
not
extern map;
 
J

John Bode

Simon said:
I'm having difficulty with a struct in two of my c files.

The header file for csd.c (the main program) contains the typedef for a
struct called tiles. There is only one struct in use (called "map")
throughout the time that the program is run, and as it's used by
virtually all of the functions it's currently a global. I realise that
this is probably bad practice but I'm still pretty far down the curve
when it comes to c.

The file org.c contains some code which alters certain of the values
within "map". I'd like to declare "map" in csd.c and then use extern
to tell org.c that it exists. Unfortunately, nothing that I do seems
to be able to achieve this. I'm definitely including the typedef in
both files, but if I put a statement like "extern map" in org.c and try
and compile it gives an error "subscripted value is neither array nor
pointer" when it gets to the line "map[j].terrain = 1;".

The only way that I can get the thing to compile is to have a header
file shared by both csd.c and org.c which contains the typedef followed
by the declaration of the global variable map. This makes me nervous
because as far as I can see the global "map" is being declared twice -
once by each of the files.

Any ideas?

Simon


Put an extern declaration of map in the header file, and put the
defining declaration of map in csd.c:

/* header file */
typedef struct ... tiles;

/*
* Makes the identifier visible to other translation units,
* but indicates that the defining occurrence is
* somewhere else.
*/
extern tiles map;

/* csd.c */

#include "header.h"
....
/*
* Defining declaration of map; this is done at file scope, outside
* of any function body.
*/
tiles map = { /* explicitly initialize members of map here */ };

This should get you running. Of course, the right way to do this is to
define the instance of map in main(), and pass it as a parameter to any
functions that need to read or manipulate it. Keep the header with the
typedef, but omit the extern declaration of map.
 
S

Simon Biber

Simon said:
I'm having difficulty with a struct in two of my c files.

The header file for csd.c (the main program) contains the typedef for a
struct called tiles. There is only one struct in use (called "map")
throughout the time that the program is run, and as it's used by
virtually all of the functions it's currently a global. I realise that
this is probably bad practice but I'm still pretty far down the curve
when it comes to c.

The file org.c contains some code which alters certain of the values
within "map". I'd like to declare "map" in csd.c and then use extern
to tell org.c that it exists. Unfortunately, nothing that I do seems
to be able to achieve this. I'm definitely including the typedef in
both files, but if I put a statement like "extern map" in org.c and try
and compile it gives an error "subscripted value is neither array nor
pointer" when it gets to the line "map[j].terrain = 1;".

The only way that I can get the thing to compile is to have a header
file shared by both csd.c and org.c which contains the typedef followed
by the declaration of the global variable map. This makes me nervous
because as far as I can see the global "map" is being declared twice -
once by each of the files.


Declaring it in a header file is the right way to go. If you put the
keyword extern before the declaration, it will not be a problem
declaring it twice. Just make sure that you don't put an initialiser on it.

You should declare it extern in the header, which is included in both
files. But you should also define it (without extern), in one of the
files only.

Below I've given an example layout for your header file. Note each of
the things in it: include guards, global constants, type definitions,
global variable declarations and function declarations.

/* map.h */

/* Include guards */

#ifndef H_MAP
#define H_MAP

/* Global constants */

#define MAP_HEIGHT 30
#define MAP_WIDTH 30

/* Type definitions */

struct tile
{
int terrain;
};

/* Global variable declarations */

extern struct tile map[MAP_HEIGHT][MAP_WIDTH];

/* Global function declarations */

void init_map(void);

#endif



/* csd.c */

#include "map.h"

/* Define map in only one of the files */

struct tile map[MAP_HEIGHT][MAP_WIDTH];

int main(void)
{
init_map();

return 0;
}



/* org.c */

#include "map.h"

void init_map(void)
{
int i, j;
for(i = 0; i < MAP_HEIGHT; i++)
{
for(j = 0; j < MAP_WIDTH; j++)
{
map[j].terrain = 1;
}
}
}



/* Example compile process for gcc */

gcc -ansi -pedantic -Wall -W -O2 -c csd.c
gcc -ansi -pedantic -Wall -W -O2 -c org.c
gcc -ansi -pedantic -Wall -W -O2 csd.o org.o -o csd
../csd
 
S

Simon

Simon said:
Declaring it in a header file is the right way to go. If you put the
keyword extern before the declaration, it will not be a problem
declaring it twice. Just make sure that you don't put an initialiser on it.

You should declare it extern in the header, which is included in both
files. But you should also define it (without extern), in one of the
files only.

Below I've given an example layout for your header file. Note each of
the things in it: include guards, global constants, type definitions,
global variable declarations and function declarations.

/* map.h */

/* Include guards */

#ifndef H_MAP
#define H_MAP

/* Global constants */

#define MAP_HEIGHT 30
#define MAP_WIDTH 30

/* Type definitions */

struct tile
{
int terrain;
};

/* Global variable declarations */

extern struct tile map[MAP_HEIGHT][MAP_WIDTH];

/* Global function declarations */

void init_map(void);

#endif



/* csd.c */

#include "map.h"

/* Define map in only one of the files */

struct tile map[MAP_HEIGHT][MAP_WIDTH];

int main(void)
{
init_map();

return 0;
}



/* org.c */

#include "map.h"

void init_map(void)
{
int i, j;
for(i = 0; i < MAP_HEIGHT; i++)
{
for(j = 0; j < MAP_WIDTH; j++)
{
map[j].terrain = 1;
}
}
}



/* Example compile process for gcc */

gcc -ansi -pedantic -Wall -W -O2 -c csd.c
gcc -ansi -pedantic -Wall -W -O2 -c org.c
gcc -ansi -pedantic -Wall -W -O2 csd.o org.o -o csd
./csd


I followed these instructions quite precisely, but the result was a bit
confusing. When I compile I now get a series of errors throughout
main() which say "invalid use of undefined type 'struct tiles'".

I also get an interesting error at the line in csd.c where I define map
(struct tile map[MAP_HEIGHT][MAP_WIDTH];) which says "storage size of
'map' isn't known".

There must be something obvious I'm missing...

Simon
 
S

Simon

Simon said:
I followed these instructions quite precisely, but the result was a bit
confusing. When I compile I now get a series of errors throughout
main() which say "invalid use of undefined type 'struct tiles'".

I also get an interesting error at the line in csd.c where I define map
(struct tile map[MAP_HEIGHT][MAP_WIDTH];) which says "storage size of
'map' isn't known".

There must be something obvious I'm missing...

Simon

Ignore that - by putting simply "extern tile..." in the header file and
then "tile map..." in the definition in csd.c it all seems to work
fine. Thanks a lot for your help!

Simon
 
J

Joe Wright

Simon said:
I'm having difficulty with a struct in two of my c files.

The header file for csd.c (the main program) contains the typedef for a
struct called tiles. There is only one struct in use (called "map")
throughout the time that the program is run, and as it's used by
virtually all of the functions it's currently a global. I realise that
this is probably bad practice but I'm still pretty far down the curve
when it comes to c.

The file org.c contains some code which alters certain of the values
within "map". I'd like to declare "map" in csd.c and then use extern
to tell org.c that it exists. Unfortunately, nothing that I do seems
to be able to achieve this. I'm definitely including the typedef in
both files, but if I put a statement like "extern map" in org.c and try
and compile it gives an error "subscripted value is neither array nor
pointer" when it gets to the line "map[j].terrain = 1;".

The only way that I can get the thing to compile is to have a header
file shared by both csd.c and org.c which contains the typedef followed
by the declaration of the global variable map. This makes me nervous
because as far as I can see the global "map" is being declared twice -
once by each of the files.

Any ideas?

Simon

An idea..

/*csd.h*/
#ifndef CSDH
#define CSDH

typedef struct {
int a;
int b;
} tiles;

void org(void);

#endif

/*org.c*/
#include "csd.h"

extern tiles map; /* map is external to org.c */

void org(void) {
map.a = 1;
map.b = 2;
}

/*csd.c*/
#include <stdio.h>
#include "csd.h"

tiles map; /* map is internal to csd.c */

int main(void) {
org();
printf("%d %d\n", map.a, map.b);
return 0;
}
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top