External structs - newbie question

Discussion in 'C Programming' started by Simon, Nov 10, 2006.

  1. Simon

    Simon Guest

    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
     
    Simon, Nov 10, 2006
    #1
    1. Advertising

  2. Simon

    Rachael Guest

    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;
     
    Rachael, Nov 10, 2006
    #2
    1. Advertising

  3. Simon

    John Bode Guest

    Simon wrote:
    > 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.
     
    John Bode, Nov 10, 2006
    #3
  4. Simon

    Simon Biber Guest

    Simon wrote:
    > 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

    --
    Simon.
     
    Simon Biber, Nov 10, 2006
    #4
  5. Simon

    Simon Guest

    Simon Biber wrote:
    >
    > 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
    >
    > --
    > Simon.


    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
     
    Simon, Nov 10, 2006
    #5
  6. Simon

    Simon Guest

    Simon wrote:
    > 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
     
    Simon, Nov 10, 2006
    #6
  7. Simon

    Joe Wright Guest

    Simon wrote:
    > 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;
    }


    --
    Joe Wright
    "Everything should be made as simple as possible, but not simpler."
    --- Albert Einstein ---
     
    Joe Wright, Nov 11, 2006
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Patricia  Van Hise

    structs with fields that are structs

    Patricia Van Hise, Apr 5, 2004, in forum: C Programming
    Replies:
    5
    Views:
    667
    Al Bowers
    Apr 5, 2004
  2. Chris Hauxwell

    const structs in other structs

    Chris Hauxwell, Apr 23, 2004, in forum: C Programming
    Replies:
    6
    Views:
    587
    Chris Hauxwell
    Apr 27, 2004
  3. Paminu
    Replies:
    5
    Views:
    660
    Eric Sosman
    Oct 11, 2005
  4. Daniel Rudy
    Replies:
    15
    Views:
    1,449
    Keith Thompson
    Apr 10, 2006
  5. Tuan  Bui
    Replies:
    14
    Views:
    526
    it_says_BALLS_on_your forehead
    Jul 29, 2005
Loading...

Share This Page