CCNA
CCNA

Reputation: 387

How is the memory allocated for an array defined (declared?) in a header file?

Say, there is a proc.h which defines an array like

proc.h:

struct proc
{
 char p_stat;
 char p_flags;
 int p_pid;
} proc[100];

And there are another 5 .c files including this header file. I did not see any of such .c files allocate the memory for this array. I think it's linker that allocates the memory for it. However, what appears in the header file should be just a declaration. How could a declaration causes the memory allocation? I thought only definition will cause the memory allocation.

Thanks,

Upvotes: 1

Views: 797

Answers (5)

M.M
M.M

Reputation: 141554

As Morten Jensen noted, it is the same as doing:

typdef struct proc
{
   // ...
} proc_t;

proc_t proc[100];

which is a definition of proc (not just a declaration). However this is probably a mistake. If this header is included in more than one translation unit, then it is undefined behaviour.

(I am posting this answer because all of the other answers so far say that it creates multiple copies of proc, however that is wrong!)

It's undefined behaviour to have two (or more) definitions of an externally-visible variable.


If the intent is to have a single variable visible from multiple units, then proc_t proc[100]; needs to be replaced with the declaration:

extern proc_t proc[100];

and then exactly one unit does the definition proc_t proc[100].

If the intent is for all units to have separate copies of proc, then replace with this definition:

static proc_t proc[100];

In both cases, proc has what is called static storage duration. This means that the memory is allocated during program startup.

Upvotes: 1

Morten Jensen
Morten Jensen

Reputation: 5936

Say, there is a proc.h which defines an array like

proc.h:

struct proc 
{  
    char p_stat;  
    char p_flags;  
    int p_pid; 
} proc[100];

The code above actually not only defines the data structure struct proc, it also declares/allocates an array of them for each file including the header.

A widely used idiom is to define the data structure with a typedef, like so:

 typedef struct 
 {  
     char p_stat;  
     char p_flags;  
     int p_pid; 
 } proc_t;

or just plain old defining the structure without the typedef:

 struct 
 {  
     char p_stat;  
     char p_flags;  
     int p_pid; 
 } proc_t;

and then in the c-file matching the header, you'll instantiate your array of structs:

proc_t proc[100];        // if you've typedef'd the struct
struct proc_t proc[100]; // if you haven't typedef'd

and then in all the c-files including the header, wanting access to this global struct, you'll declare the variable extern. That way, all the c-files will share access to a single data structure.

I prefer to typedef a structure in a single header and encapsulate it by only accessing/manipulating instantiations of that data structures through function calls (objects passed by address), but that is a matter of personal taste and whatevs.

Upvotes: 3

JVMATL
JVMATL

Reputation: 2122

'header' files are included (become part of) a C file. You have declared and defined the array in your header file and then included that declaration into your five C files, so the space gets allocated 5 times. What you want to do is make the proc array an extern declaration in the header file, and then copy the exact same declaration (without the extern) in one of your C files.

Or, you can accomplish much the same thing with macros, like so:

// foo.h
#ifndef MAIN
  /*
   * this declaration is extern for everybody except the 
   * MAIN module, (typically main.c) which defines
   * the macro MAIN -- this ensures that all C files see the same 
   * structure definition, but space is allocated exactly once.
   */
   extern struct proc {
#else
          struct proc {
#endif
     … 
    } proc[100];

in one of your C files, (e.g. main), you do this:

// main.c
#define MAIN
// when you include foo.h, the 'extern' will be left out, and space will be allocated
#include "foo.h"

in your other C files, you just do this:

// other.c
#include "foo.h"

This will cause space for the array to be allocated once (in main.o) and the other .o files will contain external references to proc[] which will be resolved by the linker.

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726569

I did not see any of such .c files allocate the memory for this array.

Actually, they all do: the declaration and the definition are copied verbatim into each translation unit that includes the header, so each translation unit gets its own definition of the proc[100] array.

If you try linking the results of translation together, you should see a redefinition error produced by the linker, unless the actual header declares proc static.

Of course the proper way of creating proc[100] would be to declare it extern in the header, and provide a definition in one of the .c files.

Upvotes: 2

Dariusz
Dariusz

Reputation: 22241

The include directive does nothing more than insert the included file into the file which includes it. In other words, all .c files declare the structure separately, and declare (allocate memory) for the variable proc. They all define memory for it separately. If all of them are later compiled together, I have no idea how can this possible work properly.

Upvotes: 2

Related Questions