142

If I have a source.c file with a struct:

struct a { 
    int i;
    struct b {
        int j;
    }
};

How can this struct be used in another file (i.e. func.c)?

Should I create a new header file, declare the struct there and include that header in func.c?

Or should I define the whole struct in a header file and include that in both source.c and func.c? How can the struct be declared extern in both files?

Should I typedef it? If so, how?

Software Engineer
  • 15,457
  • 7
  • 74
  • 102
  • Note that the structure definition is not valid C. At minimum there should be a semicolon after the close brace for `struct b`, but then your structure `a` declares a type that is unused (you should probably define a member name, perhaps `k`, after the inner close brace and before the semicolon. – Jonathan Leffler Sep 30 '14 at 23:57

3 Answers3

166

if this structure is to be used by some other file func.c how to do it?

When a type is used in a file (i.e. func.c file), it must be visible. The very worst way to do it is copy paste it in each source file needed it.

The right way is putting it in an header file, and include this header file whenever needed.

shall we open a new header file and declare the structure there and include that header in the func.c?

This is the solution I like more, because it makes the code highly modular. I would code your struct as:

#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME

struct a
{ 
    int i;
    struct b
    {
        int j;
    }
};

#endif

I would put functions using this structure in the same header (the function that are "semantically" part of its "interface").

And usually, I could name the file after the structure name, and use that name again to choose the header guards defines.

If you need to declare a function using a pointer to the struct, you won't need the full struct definition. A simple forward declaration like:

struct a ;

Will be enough, and it decreases coupling.

or can we define the total structure in header file and include that in both source.c and func.c?

This is another way, easier somewhat, but less modular: Some code needing only your structure to work would still have to include all types.

In C++, this could lead to interesting complication, but this is out of topic (no C++ tag), so I won't elaborate.

then how to declare that structure as extern in both the files. ?

I fail to see the point, perhaps, but Greg Hewgill has a very good answer in his post How to declare a structure in a header that is to be used by multiple files in c?.

shall we typedef it then how?

  • If you are using C++, don't.
  • If you are using C, you should.

The reason being that C struct managing can be a pain: You have to declare the struct keyword everywhere it is used:

struct MyStruct ; /* Forward declaration */

struct MyStruct
{
   /* etc. */
} ;

void doSomething(struct MyStruct * p) /* parameter */
{
   struct MyStruct a ; /* variable */
   /* etc */
}

While a typedef will enable you to write it without the struct keyword.

struct MyStructTag ; /* Forward declaration */

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

void doSomething(MyStruct * p) /* parameter */
{
   MyStruct a ; /* variable */
   /* etc */
}

It is important you still keep a name for the struct. Writing:

typedef struct
{
   /* etc. */
} MyStruct ;

will just create an anonymous struct with a typedef-ed name, and you won't be able to forward-declare it. So keep to the following format:

typedef struct MyStructTag
{
   /* etc. */
} MyStruct ;

Thus, you'll be able to use MyStruct everywhere you want to avoid adding the struct keyword, and still use MyStructTag when a typedef won't work (i.e. forward declaration)

Edit:

Corrected wrong assumption about C99 struct declaration, as rightfully remarked by Jonathan Leffler.

Edit 2018-06-01:

Craig Barnes reminds us in his comment that you don't need to keep separate names for the struct "tag" name and its "typedef" name, like I did above for the sake of clarity.

Indeed, the code above could well be written as:

typedef struct MyStruct
{
   /* etc. */
} MyStruct ;

IIRC, this is actually what C++ does with its simpler struct declaration, behind the scenes, to keep it compatible with C:

// C++ explicit declaration by the user
struct MyStruct
{
   /* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;

Back to C, I've seen both usages (separate names and same names), and none has drawbacks I know of, so using the same name makes reading simpler if you don't use C separate "namespaces" for structs and other symbols.

Community
  • 1
  • 1
paercebal
  • 81,378
  • 38
  • 130
  • 159
  • 2
    Can you comment on, or point out the section of the C99 standard that warrants your "If you are using C99, don't" comment? – Jonathan Leffler Nov 26 '08 at 07:53
  • You're right. I tested recently a C99 and was surprised to see that my untypedefed struct was not recognized when used the C++ way. I searched for compiler options, and then, in all standard documents I could put my hands on, but found nothing that could explain I believed it possible... – paercebal Nov 30 '08 at 20:07
  • 2
    ... So anyway, thanks for the remark. I corrected it right now. – paercebal Nov 30 '08 at 20:10
  • There's no need to use different names for the `struct` tag and the `typedef` name. C uses a different namespace for `struct` tags, so you can use `MyStruct` for both. – Craig Barnes May 31 '18 at 08:02
  • 1
    @CraigBarnes You're right, but I wanted that to be clear just by reading the code. Had I given the same name, it could have confused C newbies on the need to write the name *twice" in the same "declaration". I will add a note mentioning your comment. Thanks! – paercebal Jun 01 '18 at 08:58
42

For a structure definition that is to be used across more than one source file, you should definitely put it in a header file. Then include that header file in any source file that needs the structure.

The extern declaration is not used for structure definitions, but is instead used for variable declarations (that is, some data value with a structure type that you have defined). If you want to use the same variable across more than one source file, declare it as extern in a header file like:

extern struct a myAValue;

Then, in one source file, define the actual variable:

struct a myAValue;

If you forget to do this or accidentally define it in two source files, the linker will let you know about this.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • You might get a linker error, or you might not. In C, the linkage model allows for 'common' definitions, so multiple definitions with no initializer (and maybe with the same initializer) may work. It is a 'common extension'. Some compilers support tentative (missing) definitions too, I believe. – Jonathan Leffler Oct 23 '08 at 06:12
  • Then, in one source file, *define* the actual variable: ; ... or accidentally *define* it in two source files ... :) – Johannes Schaub - litb Nov 25 '08 at 19:34
  • One technique I've used for the declare/define issue is to conditionally define `GLOBAL` as `extern` or nothing at the top of the header and then declare variables as `GLOBAL struct a myAValue;`. From most source files, you arrange for the `#define GLOBAL extern` version to be used (_declaring_ the variables) and from exactly one source file it causes the empty define to be used so the variables are _defined_. – TripeHound Mar 18 '14 at 16:37
  • You can have the structure name same as the typedef name in C, but not in C++. – xuhdev Jun 27 '14 at 05:46
9

a.h:

#ifndef A_H
#define A_H

struct a { 
    int i;
    struct b {
        int j;
    }
};

#endif

there you go, now you just need to include a.h to the files where you want to use this structure.

Software Engineer
  • 15,457
  • 7
  • 74
  • 102
fmsf
  • 36,317
  • 49
  • 147
  • 195