How do I use extern to share variables between source files? The Next CEO of Stack OverflowHow do I share variables between different .c files?Variable declaration in a header fileUse of 'extern' KeywordWhy use the extern keyword in header in C?Where can I declare global variable in c program , whether in header or source fileAre there any drawbacks to declaring variables in header files without the “extern” keyword?C++ How to properly initialize global variables?C globally shared variable vs extern variableGlobal variable in csame static variable in different filesHow to declare global variables in Android?Improve INSERT-per-second performance of SQLite?Why won't extern link to a static variable?Global variables in Javascript across multiple filesshared global variables in CShare variables between files in Node.js?What does the C ??!??! operator do?Global variables in AngularJSHow to declare and use global external variable across multiple source files?Are global variables by default extern? if yes, then why they have default value “ 0 ”?

Why can't we say "I have been having a dog"?

My boss doesn't want me to have a side project

Can I cast Thunderwave and be at the center of its bottom face, but not be affected by it?

Would a grinding machine be a simple and workable propulsion system for an interplanetary spacecraft?

How does a dynamic QR code work?

How can I separate the number from the unit in argument?

Shortening a title without changing its meaning

Can you teleport closer to a creature you are Frightened of?

Direct Implications Between USA and UK in Event of No-Deal Brexit

Free fall ellipse or parabola?

What did the word "leisure" mean in late 18th Century usage?

How to unfasten electrical subpanel attached with ramset

Horror film about a man brought out of cryogenic suspension without a soul, around 1990

The sum of any ten consecutive numbers from a fibonacci sequence is divisible by 11

Find a path from s to t using as few red nodes as possible

What difference does it make matching a word with/without a trailing whitespace?

Physiological effects of huge anime eyes

Is the offspring between a demon and a celestial possible? If so what is it called and is it in a book somewhere?

Simplify trigonometric expression using trigonometric identities

Find the majority element, which appears more than half the time

Gauss' Posthumous Publications?

Are British MPs missing the point, with these 'Indicative Votes'?

Salesforce opportunity stages

Is a linearly independent set whose span is dense a Schauder basis?



How do I use extern to share variables between source files?



The Next CEO of Stack OverflowHow do I share variables between different .c files?Variable declaration in a header fileUse of 'extern' KeywordWhy use the extern keyword in header in C?Where can I declare global variable in c program , whether in header or source fileAre there any drawbacks to declaring variables in header files without the “extern” keyword?C++ How to properly initialize global variables?C globally shared variable vs extern variableGlobal variable in csame static variable in different filesHow to declare global variables in Android?Improve INSERT-per-second performance of SQLite?Why won't extern link to a static variable?Global variables in Javascript across multiple filesshared global variables in CShare variables between files in Node.js?What does the C ??!??! operator do?Global variables in AngularJSHow to declare and use global external variable across multiple source files?Are global variables by default extern? if yes, then why they have default value “ 0 ”?










878















I know that global variables in C sometimes have the extern keyword. What is an extern variable? What is the declaration like? What is its scope?



This is related to sharing variables across source files, but how does that work precisely? Where do I use extern?










share|improve this question




























    878















    I know that global variables in C sometimes have the extern keyword. What is an extern variable? What is the declaration like? What is its scope?



    This is related to sharing variables across source files, but how does that work precisely? Where do I use extern?










    share|improve this question


























      878












      878








      878


      831






      I know that global variables in C sometimes have the extern keyword. What is an extern variable? What is the declaration like? What is its scope?



      This is related to sharing variables across source files, but how does that work precisely? Where do I use extern?










      share|improve this question
















      I know that global variables in C sometimes have the extern keyword. What is an extern variable? What is the declaration like? What is its scope?



      This is related to sharing variables across source files, but how does that work precisely? Where do I use extern?







      c global-variables extern






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 22 '17 at 7:01









      Lundin

      112k17163271




      112k17163271










      asked Sep 16 '09 at 14:08







      shilpa





























          16 Answers
          16






          active

          oldest

          votes


















          1583





          +100









          Using extern is only of relevance when the program you're building
          consists of multiple source files linked together, where some of the
          variables defined, for example, in source file file1.c need to be
          referenced in other source files, such as file2.c.



          It is important to understand the difference between defining a
          variable and declaring a
          variable:



          • A variable is declared when the compiler is informed that a
            variable exists (and this is its type); it does not allocate the
            storage for the variable at that point.

          • A variable is defined when the compiler allocates the storage for
            the variable.

          You may declare a variable multiple times (though once is sufficient);
          you may only define it once within a given scope.
          A variable definition is also a declaration, but not all variable
          declarations are definitions.



          Best way to declare and define global variables



          The clean, reliable way to declare and define global variables is to use
          a header file to contain an extern declaration of the variable.



          The header is included by the one source file that defines the variable
          and by all the source files that reference the variable.
          For each program, one source file (and only one source file) defines the
          variable.
          Similarly, one header file (and only one header file) should declare the
          variable.
          The header file is crucial; it enables cross-checking between
          independent TUs (translation units — think source files) and ensures
          consistency.



          Although there are other ways of doing it, this method is simple and
          reliable.
          It is demonstrated by file3.h, file1.c and file2.c:



          file3.h



          extern int global_variable; /* Declaration of the variable */


          file1.c



          #include "file3.h" /* Declaration made available here */
          #include "prog1.h" /* Function declarations */

          /* Variable defined here */
          int global_variable = 37; /* Definition checked against declaration */

          int increment(void) return global_variable++;


          file2.c



          #include "file3.h"
          #include "prog1.h"
          #include <stdio.h>

          void use_it(void)

          printf("Global variable: %dn", global_variable++);



          That's the best way to declare and define global variables.




          The next two files complete the source for prog1:



          The complete programs shown use functions, so function declarations have
          crept in.
          Both C99 and C11 require functions to be declared or defined before they
          are used (whereas C90 did not, for good reasons).
          I use the keyword extern in front of function declarations in headers
          for consistency — to match the extern in front of variable
          declarations in headers.
          Many people prefer not to use extern in front of function
          declarations; the compiler doesn't care — and ultimately, neither do I
          as long as you're consistent, at least within a source file.



          prog1.h



          extern void use_it(void);
          extern int increment(void);


          prog1.c



          #include "file3.h"
          #include "prog1.h"
          #include <stdio.h>

          int main(void)

          use_it();
          global_variable += 19;
          use_it();
          printf("Increment: %dn", increment());
          return 0;




          • prog1 uses prog1.c, file1.c, file2.c, file3.h and prog1.h.

          The file prog1.mk is a makefile for prog1 only.
          It will work with most versions of make produced since about the turn
          of the millennium.
          It is not tied specifically to GNU Make.



          prog1.mk



          # Minimal makefile for prog1

          PROGRAM = prog1
          FILES.c = prog1.c file1.c file2.c
          FILES.h = prog1.h file3.h
          FILES.o = $FILES.c:.c=.o

          CC = gcc
          SFLAGS = -std=c11
          GFLAGS = -g
          OFLAGS = -O3
          WFLAG1 = -Wall
          WFLAG2 = -Wextra
          WFLAG3 = -Werror
          WFLAG4 = -Wstrict-prototypes
          WFLAG5 = -Wmissing-prototypes
          WFLAGS = $WFLAG1 $WFLAG2 $WFLAG3 $WFLAG4 $WFLAG5
          UFLAGS = # Set on command line only

          CFLAGS = $SFLAGS $GFLAGS $OFLAGS $WFLAGS $UFLAGS
          LDFLAGS =
          LDLIBS =

          all: $PROGRAM

          $PROGRAM: $FILES.o
          $CC -o $@ $CFLAGS $FILES.o $LDFLAGS $LDLIBS

          prog1.o: $FILES.h
          file1.o: $FILES.h
          file2.o: $FILES.h

          # If it exists, prog1.dSYM is a directory on macOS
          DEBRIS = a.out core *~ *.dSYM
          RM_FR = rm -fr

          clean:
          $RM_FR $FILES.o $PROGRAM $DEBRIS



          Guidelines



          Rules to be broken by experts only, and only with good reason:



          • A header file only contains extern declarations of variables — never
            static or unqualified variable definitions.

          • For any given variable, only one header file declares it (SPOT —
            Single Point of Truth).

          • A source file never contains extern declarations of variables —
            source files always include the (sole) header that declares them.

          • For any given variable, exactly one source file defines the variable,
            preferably initializing it too. (Although there is no need to
            initialize explicitly to zero, it does no harm and can do some good,
            because there can be only one initialized definition of a particular
            global variable in a program).

          • The source file that defines the variable also includes the header to
            ensure that the definition and the declaration are consistent.

          • A function should never need to declare a variable using extern.

          • Avoid global variables whenever possible — use functions instead.

          The source code and text of this answer are available in my
          SOQ (Stack Overflow Questions)
          repository on GitHub in the
          src/so-0143-3204
          sub-directory.



          If you're not an experienced C programmer, you could (and perhaps
          should) stop reading here.



          Not so good way to define global variables



          With some (indeed, many) C compilers, you can get away with what's
          called a 'common' definition of a variable too.
          'Common', here, refers to a technique used in Fortran for sharing
          variables between source files, using a (possibly named) COMMON block.
          What happens here is that each of a number of files provides a tentative
          definition of the variable.
          As long as no more than one file provides an initialized definition,
          then the various files end up sharing a common single definition of the
          variable:



          file10.c



          #include "prog2.h"

          int i; /* Do not do this in portable code */

          void inc(void) i++;


          file11.c



          #include "prog2.h"

          int i; /* Do not do this in portable code */

          void dec(void) i--;


          file12.c



          #include "prog2.h"
          #include <stdio.h>

          int i = 9; /* Do not do this in portable code */

          void put(void) printf("i = %dn", i);


          This technique does not conform to the letter of the C standard and the
          'one definition rule' — it is officially undefined behaviour:




          J.2 Undefined behavior



          An identifier with external linkage is used, but in the program there
          does not exist exactly one external definition for the identifier, or
          the identifier is not used and there exist multiple external
          definitions for the identifier (6.9).



          §6.9 External definitions ¶5



          An external definition is an external declaration that is also a
          definition of a function (other than an inline definition) or an
          object.
          If an identifier declared with external linkage is used in an
          expression (other than as part of the operand of a sizeof or
          _Alignof operator whose result is an integer constant), somewhere in
          the entire program there shall be exactly one external definition for
          the identifier; otherwise, there shall be no more than
          one.161)



          161) Thus, if an identifier declared with external linkage
          is not used in an expression, there need be no external definition for
          it.




          However, the C standard also lists it in informative Annex J as one of
          the Common extensions.




          J.5.11 Multiple external definitions



          There may be more than one external definition for the identifier of
          an object, with or without the explicit use of the keyword extern; if
          the definitions disagree, or more than one is initialized, the
          behavior is undefined (6.9.2).




          Because this technique is not always supported, it is best to avoid
          using it, especially if your code needs to be portable.
          Using this technique, you can also end up with unintentional type
          punning.
          If one of the files declared i as a double instead of as an int,
          C's type-unsafe linkers probably would not spot the mismatch.
          If you're on a machine with 64-bit int and double, you'd not even
          get a warning; on a machine with 32-bit int and 64-bit double, you'd
          probably get a warning about the different sizes — the linker would
          use the largest size, exactly as a Fortran program would take the
          largest size of any common blocks.




          The next two files complete the source for prog2:



          prog2.h



          extern void dec(void);
          extern void put(void);
          extern void inc(void);


          prog2.c



          #include "prog2.h"
          #include <stdio.h>

          int main(void)

          inc();
          put();
          dec();
          put();
          dec();
          put();




          • prog2 uses prog2.c, file10.c, file11.c, file12.c, prog2.h.


          Warning



          As noted in comments here, and as stated in my answer to a similar
          question, using multiple
          definitions for a global variable leads to undefined behaviour (J.2;
          §6.9), which is the standard's way of saying "anything could happen".
          One of the things that can happen is that the program behaves as you
          expect; and J.5.11 says, approximately, "you might be lucky more often
          than you deserve".
          But a program that relies on multiple definitions of an extern variable
          — with or without the explicit 'extern' keyword — is not a strictly
          conforming program and not guaranteed to work everywhere.
          Equivalently: it contains a bug which may or may not show itself.



          Violating the guidelines



          There are, of course, many ways in which these guidelines can be broken.
          Occasionally, there may be a good reason to break the guidelines, but
          such occasions are extremely unusual.



          faulty_header.h



          int some_var; /* Do not do this in a header!!! */


          Note 1: if the header defines the variable without the extern keyword,
          then each file that includes the header creates a tentative definition
          of the variable.
          As noted previously, this will often work, but the C standard does not
          guarantee that it will work.



          broken_header.h



          int some_var = 13; /* Only one source file in a program can use this */


          Note 2: if the header defines and initializes the variable, then only
          one source file in a given program can use the header.
          Since headers are primarily for sharing information, it is a bit silly
          to create one that can only be used once.



          seldom_correct.h



          static int hidden_global = 3; /* Each source file gets its own copy */


          Note 3: if the header defines a static variable (with or without
          initialization), then each source file ends up with its own private
          version of the 'global' variable.



          If the variable is actually a complex array, for example, this can lead
          to extreme duplication of code. It can, very occasionally, be a
          sensible way to achieve some effect, but that is very unusual.




          Summary



          Use the header technique I showed first.
          It works reliably and everywhere.
          Note, in particular, that the header declaring the global_variable is
          included in every file that uses it — including the one that defines it.
          This ensures that everything is self-consistent.



          Similar concerns arise with declaring and defining functions —
          analogous rules apply.
          But the question was about variables specifically, so I've kept the
          answer to variables only.



          End of Original Answer



          If you're not an experienced C programmer, you probably should stop reading here.




          Late Major Addition



          Avoiding Code Duplication



          One concern that is sometimes (and legitimately) raised about the
          'declarations in headers, definitions in source' mechanism described
          here is that there are two files to be kept synchronized — the header
          and the source. This is usually followed up with an observation that a
          macro can be used so that the header serves double duty — normally
          declaring the variables, but when a specific macro is set before the
          header is included, it defines the variables instead.



          Another concern can be that the variables need to be defined in each of
          a number of 'main programs'. This is normally a spurious concern; you
          can simply introduce a C source file to define the variables and link
          the object file produced with each of the programs.



          A typical scheme works like this, using the original global variable
          illustrated in file3.h:



          file3a.h



          #ifdef DEFINE_VARIABLES
          #define EXTERN /* nothing */
          #else
          #define EXTERN extern
          #endif /* DEFINE_VARIABLES */

          EXTERN int global_variable;


          file1a.c



          #define DEFINE_VARIABLES
          #include "file3a.h" /* Variable defined - but not initialized */
          #include "prog3.h"

          int increment(void) return global_variable++;


          file2a.c



          #include "file3a.h"
          #include "prog3.h"
          #include <stdio.h>

          void use_it(void)

          printf("Global variable: %dn", global_variable++);




          The next two files complete the source for prog3:



          prog3.h



          extern void use_it(void);
          extern int increment(void);


          prog3.c



          #include "file3a.h"
          #include "prog3.h"
          #include <stdio.h>

          int main(void)

          use_it();
          global_variable += 19;
          use_it();
          printf("Increment: %dn", increment());
          return 0;




          • prog3 uses prog3.c, file1a.c, file2a.c, file3a.h, prog3.h.


          Variable initialization



          The problem with this scheme as shown is that it does not provide for
          initialization of the global variable. With C99 or C11 and variable argument
          lists for macros, you could define a macro to support initialization too.
          (With C89 and no support for variable argument lists in macros, there is no
          easy way to handle arbitrarily long initializers.)



          file3b.h



          #ifdef DEFINE_VARIABLES
          #define EXTERN /* nothing */
          #define INITIALIZER(...) = __VA_ARGS__
          #else
          #define EXTERN extern
          #define INITIALIZER(...) /* nothing */
          #endif /* DEFINE_VARIABLES */

          EXTERN int global_variable INITIALIZER(37);
          EXTERN struct int a; int b; oddball_struct INITIALIZER( 41, 43 );


          Reverse contents of #if and #else blocks, fixing bug identified by
          Denis Kniazhev



          file1b.c



          #define DEFINE_VARIABLES
          #include "file3b.h" /* Variables now defined and initialized */
          #include "prog4.h"

          int increment(void) return global_variable++;
          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


          file2b.c



          #include "file3b.h"
          #include "prog4.h"
          #include <stdio.h>

          void use_them(void)

          printf("Global variable: %dn", global_variable++);
          oddball_struct.a += global_variable;
          oddball_struct.b -= global_variable / 2;



          Clearly, the code for the oddball structure is not what you'd normally
          write, but it illustrates the point. The first argument to the second
          invocation of INITIALIZER is 41 and the remaining argument
          (singular in this example) is 43 . Without C99 or similar support
          for variable argument lists for macros, initializers that need to
          contain commas are very problematic.



          Correct header file3b.h included (instead of fileba.h) per
          Denis Kniazhev




          The next two files complete the source for prog4:



          prog4.h



          extern int increment(void);
          extern int oddball_value(void);
          extern void use_them(void);


          prog4.c



          #include "file3b.h"
          #include "prog4.h"
          #include <stdio.h>

          int main(void)

          use_them();
          global_variable += 19;
          use_them();
          printf("Increment: %dn", increment());
          printf("Oddball: %dn", oddball_value());
          return 0;




          • prog4 uses prog4.c, file1b.c, file2b.c, prog4.h, file3b.h.


          Header Guards



          Any header should be protected against reinclusion, so that type
          definitions (enum, struct or union types, or typedefs generally) do not
          cause problems. The standard technique is to wrap the body of the
          header in a header guard such as:



          #ifndef FILE3B_H_INCLUDED
          #define FILE3B_H_INCLUDED

          ...contents of header...

          #endif /* FILE3B_H_INCLUDED */


          The header might be included twice indirectly. For example, if
          file4b.h includes file3b.h for a type definition that isn't shown,
          and file1b.c needs to use both header file4b.h and file3b.h, then
          you have some more tricky issues to resolve. Clearly, you might revise
          the header list to include just file4b.h. However, you might not be
          aware of the internal dependencies — and the code should, ideally,
          continue to work.



          Further, it starts to get tricky because you might include file4b.h
          before including file3b.h to generate the definitions, but the normal
          header guards on file3b.h would prevent the header being reincluded.



          So, you need to include the body of file3b.h at most once for
          declarations, and at most once for definitions, but you might need both
          in a single translation unit (TU — a combination of a source file and
          the headers it uses).



          Multiple inclusion with variable definitions



          However, it can be done subject to a not too unreasonable constraint.
          Let's introduce a new set of file names:




          • external.h for the EXTERN macro definitions, etc.


          • file1c.h to define types (notably, struct oddball, the type of oddball_struct).


          • file2c.h to define or declare the global variables.


          • file3c.c which defines the global variables.


          • file4c.c which simply uses the global variables.


          • file5c.c which shows that you can declare and then define the global variables.


          • file6c.c which shows that you can define and then (attempt to) declare the global variables.

          In these examples, file5c.c and file6c.c directly include the header
          file2c.h several times, but that is the simplest way to show that the
          mechanism works. It means that if the header was indirectly included
          twice, it would also be safe.



          The restrictions for this to work are:



          1. The header defining or declaring the global variables may not itself
            define any types.

          2. Immediately before you include a header that should define variables,
            you define the macro DEFINE_VARIABLES.

          3. The header defining or declaring the variables has stylized contents.

          external.h



          /*
          ** This header must not contain header guards (like <assert.h> must not).
          ** Each time it is invoked, it redefines the macros EXTERN, INITIALIZE
          ** based on whether macro DEFINE_VARIABLES is currently defined.
          */
          #undef EXTERN
          #undef INITIALIZE

          #ifdef DEFINE_VARIABLES
          #define EXTERN /* nothing */
          #define INITIALIZE(...) = __VA_ARGS__
          #else
          #define EXTERN extern
          #define INITIALIZE(...) /* nothing */
          #endif /* DEFINE_VARIABLES */


          file1c.h



          #ifndef FILE1C_H_INCLUDED
          #define FILE1C_H_INCLUDED

          struct oddball

          int a;
          int b;
          ;

          extern void use_them(void);
          extern int increment(void);
          extern int oddball_value(void);

          #endif /* FILE1C_H_INCLUDED */


          file2c.h



          /* Standard prologue */
          #if defined(DEFINE_VARIABLES) && !defined(FILE2C_H_DEFINITIONS)
          #undef FILE2C_H_INCLUDED
          #endif

          #ifndef FILE2C_H_INCLUDED
          #define FILE2C_H_INCLUDED

          #include "external.h" /* Support macros EXTERN, INITIALIZE */
          #include "file1c.h" /* Type definition for struct oddball */

          #if !defined(DEFINE_VARIABLES) || !defined(FILE2C_H_DEFINITIONS)

          /* Global variable declarations / definitions */
          EXTERN int global_variable INITIALIZE(37);
          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

          #endif /* !DEFINE_VARIABLES || !FILE2C_H_DEFINITIONS */

          /* Standard epilogue */
          #ifdef DEFINE_VARIABLES
          #define FILE2C_H_DEFINITIONS
          #endif /* DEFINE_VARIABLES */

          #endif /* FILE2C_H_INCLUDED */


          file3c.c



          #define DEFINE_VARIABLES
          #include "file2c.h" /* Variables now defined and initialized */

          int increment(void) return global_variable++;
          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


          file4c.c



          #include "file2c.h"
          #include <stdio.h>

          void use_them(void)

          printf("Global variable: %dn", global_variable++);
          oddball_struct.a += global_variable;
          oddball_struct.b -= global_variable / 2;



          file5c.c



          #include "file2c.h" /* Declare variables */

          #define DEFINE_VARIABLES
          #include "file2c.h" /* Variables now defined and initialized */

          int increment(void) return global_variable++;
          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


          file6c.c



          #define DEFINE_VARIABLES
          #include "file2c.h" /* Variables now defined and initialized */

          #include "file2c.h" /* Declare variables */

          int increment(void) return global_variable++;
          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



          The next source file completes the source (provides a main program) for prog5, prog6 and prog7:



          prog5.c



          #include "file2c.h"
          #include <stdio.h>

          int main(void)

          use_them();
          global_variable += 19;
          use_them();
          printf("Increment: %dn", increment());
          printf("Oddball: %dn", oddball_value());
          return 0;




          • prog5 uses prog5.c, file3c.c, file4c.c, file1c.h, file2c.h, external.h.


          • prog6 uses prog5.c, file5c.c, file4c.c, file1c.h, file2c.h, external.h.


          • prog7 uses prog5.c, file6c.c, file4c.c, file1c.h, file2c.h, external.h.


          This scheme avoids most problems. You only run into a problem if a
          header that defines variables (such as file2c.h) is included by
          another header (say file7c.h) that defines variables. There isn't an
          easy way around that other than "don't do it".



          You can partially work around the problem by revising file2c.h into
          file2d.h:



          file2d.h



          /* Standard prologue */
          #if defined(DEFINE_VARIABLES) && !defined(FILE2D_H_DEFINITIONS)
          #undef FILE2D_H_INCLUDED
          #endif

          #ifndef FILE2D_H_INCLUDED
          #define FILE2D_H_INCLUDED

          #include "external.h" /* Support macros EXTERN, INITIALIZE */
          #include "file1c.h" /* Type definition for struct oddball */

          #if !defined(DEFINE_VARIABLES) || !defined(FILE2D_H_DEFINITIONS)

          /* Global variable declarations / definitions */
          EXTERN int global_variable INITIALIZE(37);
          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

          #endif /* !DEFINE_VARIABLES || !FILE2D_H_DEFINITIONS */

          /* Standard epilogue */
          #ifdef DEFINE_VARIABLES
          #define FILE2D_H_DEFINITIONS
          #undef DEFINE_VARIABLES
          #endif /* DEFINE_VARIABLES */

          #endif /* FILE2D_H_INCLUDED */


          The issue becomes 'should the header include #undef DEFINE_VARIABLES?'
          If you omit that from the header and wrap any defining invocation with
          #define and #undef:



          #define DEFINE_VARIABLES
          #include "file2c.h"
          #undef DEFINE_VARIABLES


          in the source code (so the headers never alter the value of
          DEFINE_VARIABLES), then you should be clean. It is just a nuisance to
          have to remember to write the the extra line. An alternative might be:



          #define HEADER_DEFINING_VARIABLES "file2c.h"
          #include "externdef.h"


          externdef.h



          /*
          ** This header must not contain header guards (like <assert.h> must not).
          ** Each time it is included, the macro HEADER_DEFINING_VARIABLES should
          ** be defined with the name (in quotes - or possibly angle brackets) of
          ** the header to be included that defines variables when the macro
          ** DEFINE_VARIABLES is defined. See also: external.h (which uses
          ** DEFINE_VARIABLES and defines macros EXTERN and INITIALIZE
          ** appropriately).
          **
          ** #define HEADER_DEFINING_VARIABLES "file2c.h"
          ** #include "externdef.h"
          */

          #if defined(HEADER_DEFINING_VARIABLES)
          #define DEFINE_VARIABLES
          #include HEADER_DEFINING_VARIABLES
          #undef DEFINE_VARIABLES
          #undef HEADER_DEFINING_VARIABLES
          #endif /* HEADER_DEFINING_VARIABLES */


          This is getting a tad convoluted, but seems to be secure (using the
          file2d.h, with no #undef DEFINE_VARIABLES in the file2d.h).



          file7c.c



          /* Declare variables */
          #include "file2d.h"

          /* Define variables */
          #define HEADER_DEFINING_VARIABLES "file2d.h"
          #include "externdef.h"

          /* Declare variables - again */
          #include "file2d.h"

          /* Define variables - again */
          #define HEADER_DEFINING_VARIABLES "file2d.h"
          #include "externdef.h"

          int increment(void) return global_variable++;
          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


          file8c.h



          /* Standard prologue */
          #if defined(DEFINE_VARIABLES) && !defined(FILE8C_H_DEFINITIONS)
          #undef FILE8C_H_INCLUDED
          #endif

          #ifndef FILE8C_H_INCLUDED
          #define FILE8C_H_INCLUDED

          #include "external.h" /* Support macros EXTERN, INITIALIZE */
          #include "file2d.h" /* struct oddball */

          #if !defined(DEFINE_VARIABLES) || !defined(FILE8C_H_DEFINITIONS)

          /* Global variable declarations / definitions */
          EXTERN struct oddball another INITIALIZE( 14, 34 );

          #endif /* !DEFINE_VARIABLES || !FILE8C_H_DEFINITIONS */

          /* Standard epilogue */
          #ifdef DEFINE_VARIABLES
          #define FILE8C_H_DEFINITIONS
          #endif /* DEFINE_VARIABLES */

          #endif /* FILE8C_H_INCLUDED */


          file8c.c



          /* Define variables */
          #define HEADER_DEFINING_VARIABLES "file2d.h"
          #include "externdef.h"

          /* Define variables */
          #define HEADER_DEFINING_VARIABLES "file8c.h"
          #include "externdef.h"

          int increment(void) return global_variable++;
          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



          The next two files complete the source for prog8 and prog9:



          prog8.c



          #include "file2d.h"
          #include <stdio.h>

          int main(void)

          use_them();
          global_variable += 19;
          use_them();
          printf("Increment: %dn", increment());
          printf("Oddball: %dn", oddball_value());
          return 0;



          file9c.c



          #include "file2d.h"
          #include <stdio.h>

          void use_them(void)

          printf("Global variable: %dn", global_variable++);
          oddball_struct.a += global_variable;
          oddball_struct.b -= global_variable / 2;




          • prog8 uses prog8.c, file7c.c, file9c.c.


          • prog9 uses prog8.c, file8c.c, file9c.c.


          However, the problems are relatively unlikely to occur in practice,
          especially if you take the standard advice to



          Avoid global variables




          Does this exposition miss anything?



          Confession: The 'avoiding duplicated code' scheme outlined here was
          developed because the issue affects some code I work on (but don't own),
          and is a niggling concern with the scheme outlined in the first part of
          the answer. However, the original scheme leaves you with just two
          places to modify to keep variable definitions and declarations
          synchronized, which is a big step forward over having exernal variable
          declarations scattered throughout the code base (which really matters
          when there are thousands of files in total). However, the code in the
          files with the names fileNc.[ch] (plus external.h and externdef.h)
          shows that it can be made to work. Clearly, it would not be hard to
          create a header generator script to give you the standardized template
          for a variable defining and declaring header file.



          NB These are toy programs with just barely enough code to make them
          marginally interesting. There is repetition within the examples that
          could be removed, but isn't to simplify the pedagogical explanation.
          (For example: the difference between prog5.c and prog8.c is the name
          of one of the headers that are included. It would be possible to
          reorganize the code so that the main() function was not repeated, but
          it would conceal more than it revealed.)






          share|improve this answer




















          • 3





            @litb: see Annex J.5.11 for the common definition - it is a common extension.

            – Jonathan Leffler
            Sep 16 '09 at 15:19






          • 3





            @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

            – Jonathan Leffler
            Sep 16 '09 at 15:20






          • 3





            Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

            – Johannes Schaub - litb
            Sep 16 '09 at 15:30






          • 3





            @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

            – Jonathan Leffler
            Jan 16 '13 at 2:14






          • 11





            If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

            – Jonathan Leffler
            Aug 5 '14 at 3:28


















          112














          An extern variable is a declaration (thanks to sbi for the correction) of a variable which is defined in another translation unit. That means the storage for the variable is allocated in another file.



          Say you have two .c-files test1.c and test2.c. If you define a global variable int test1_var; in test1.c and you'd like to access this variable in test2.c you have to use extern int test1_var; in test2.c.



          Complete sample:



          $ cat test1.c 
          int test1_var = 5;
          $ cat test2.c
          #include <stdio.h>

          extern int test1_var;

          int main(void)
          printf("test1_var = %dn", test1_var);
          return 0;

          $ gcc test1.c test2.c -o test
          $ ./test
          test1_var = 5





          share|improve this answer




















          • 18





            There's no "pseudo-definitions". It's a declaration.

            – sbi
            Sep 16 '09 at 14:18






          • 1





            In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

            – radiohead
            Mar 24 '18 at 3:15







          • 2





            @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

            – Jonathan Leffler
            Jun 16 '18 at 19:44



















          36














          Extern is the keyword you use to declare that the variable itself resides in another translation unit.



          So you can decide to use a variable in a translation unit and then access it from another one, then in the second one you declare it as extern and the symbol will be resolved by the linker.



          If you don't declare it as extern you'll get 2 variables named the same but not related at all, and an error of multiple definitions of the variable.






          share|improve this answer




















          • 5





            In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

            – mjv
            Sep 16 '09 at 14:19


















          24














          I like to think of an extern variable as a promise that you make to the compiler.



          When encountering an extern, the compiler can only find out its type, not where it "lives", so it can't resolve the reference.



          You are telling it, "Trust me. At link time this reference will be resolvable."






          share|improve this answer























          • More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

            – Lie Ryan
            Nov 30 '10 at 2:16


















          18














          extern tells the compiler to trust you that the memory for this variable is declared elsewhere, so it doesnt try to allocate/check memory.



          Therefore, you can compile a file that has reference to an extern, but you can not link if that memory is not declared somewhere.



          Useful for global variables and libraries, but dangerous because the linker does not type check.






          share|improve this answer























          • The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

            – sbi
            Sep 16 '09 at 14:37


















          15














          Adding an extern turns a variable definition into a variable declaration. See this thread as to what's the difference between a declaration and a definition.






          share|improve this answer

























          • What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

            – user1150105
            Nov 8 '12 at 19:07











          • @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

            – sbi
            Nov 9 '12 at 9:12



















          11














          The correct interpretation of extern is that you tell something to the compiler. You tell the compiler that, despite not being present right now, the variable declared will somehow be found by the linker (typically in another object (file)). The linker will then be the lucky guy to find everything and put it together, whether you had some extern declarations or not.






          share|improve this answer






























            8














            In C a variable inside a file say example.c is given local scope. The compiler expects that the variable would have its definition inside the same file example.c and when it does not find the same , it would throw an error.A function on the other hand has by default global scope . Thus you do not have to explicitly mention to the compiler "look dude...you might find the definition of this function here". For a function including the file which contains its declaration is enough.(The file which you actually call a header file).
            For example consider the following 2 files :

            example.c



            #include<stdio.h>
            extern int a;
            main()
            printf("The value of a is <%d>n",a);



            example1.c



            int a = 5;


            Now when you compile the two files together, using the following commands :



            step 1)cc -o ex example.c example1.c
            step 2)./ex



            You get the following output : The value of a is <5>






            share|improve this answer
































              7














              extern keyword is used with the variable for its identification as a global variable.




              It also represents that you can use the variable declared using extern
              keyword in any file though it is declared/defined in other file.







              share|improve this answer






























                6














                GCC ELF Linux implementation



                main.c:



                #include <stdio.h>

                int not_extern_int = 1;
                extern int extern_int;

                void main()
                printf("%dn", not_extern_int);
                printf("%dn", extern_int);



                Compile and decompile:



                gcc -c main.c
                readelf -s main.o


                Output contains:



                Num: Value Size Type Bind Vis Ndx Name
                9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 not_extern_int
                12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND extern_int


                The System V ABI Update ELF spec "Symbol Table" chapter explains:




                SHN_UNDEF This section table index means the symbol is undefined. When the link editor combines this object file with another that defines the indicated symbol, this file's references to the symbol will be linked to the actual definition.




                which is basically the behavior the C standard gives to extern variables.



                From now on, it is the job of the linker to make the final program, but the extern information has already been extracted from the source code into the object file.



                Tested on GCC 4.8.



                C++17 inline variables



                In C++17, you might want to use inline variables instead of extern ones, as they are simple to use (can be defined just once on header) and more powerful (support constexpr). See: What does 'const static' mean in C and C++?






                share|improve this answer




















                • 3





                  It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                  – Jonathan Leffler
                  Aug 30 '15 at 14:57












                • @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                  – Ciro Santilli 新疆改造中心 六四事件 法轮功
                  Sep 2 '15 at 14:52












                • As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                  – Jonathan Leffler
                  Sep 2 '15 at 14:56



















                5














                extern
                allows one module of your program to access a global variable or function declared in another module of your program.
                You usually have extern variables declared in header files.



                If you don't want a program to access your variables or functions, you use static which tells the compiler that this variable or function cannot be used outside of this module.






                share|improve this answer
































                  5














                  extern simply means a variable is defined elsewhere (e.g., in another file).






                  share|improve this answer
































                    4














                    First off, the extern keyword is not used for defining a variable; rather it is used for declaring a variable. I can say extern is a storage class, not a data type.



                    extern is used to let other C files or external components know this variable is already defined somewhere. Example: if you are building a library, no need to define global variable mandatorily somewhere in library itself. The library will be compiled directly, but while linking the file, it checks for the definition.






                    share|improve this answer
































                      4














                       declare | define | initialize |
                      ----------------------------------

                      extern int a; yes no no
                      -------------
                      int a = 2019; yes yes yes
                      -------------
                      int a; yes yes no
                      -------------


                      Declaration won't allocate memory (the variable must be defined for memory allocation) but the definition will.
                      This is just another simple view on the extern keyword since the other answers are really great.






                      share|improve this answer
































                        3














                        extern is used so one first.c file can have full access to a global parameter in another second.c file.



                        The extern can be declared in the first.c file or in any of the header files first.c includes.






                        share|improve this answer




















                        • 3





                          Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                          – Jonathan Leffler
                          Sep 2 '15 at 15:09


















                        1














                        With xc8 you have to be careful about declaring a variable
                        as the same type in each file as you could , erroneously,
                        declare something an int in one file and a char say in another.
                        This could lead to corruption of variables.



                        This problem was elegantly solved in a microchip forum some 15 years ago
                        /* See "http:www.htsoft.com" /
                        /
                        "forum/all/showflat.php/Cat/0/Number/18766/an/0/page/0#18766"



                        But this link seems to no longer work...



                        So I;ll quickly try to explain it;
                        make a file called global.h.



                        In it declare the following



                        #ifdef MAIN_C
                        #define GLOBAL
                        /* #warning COMPILING MAIN.C */
                        #else
                        #define GLOBAL extern
                        #endif
                        GLOBAL unsigned char testing_mode; // example var used in several C files


                        Now in the file main.c



                        #define MAIN_C 1
                        #include "global.h"
                        #undef MAIN_C


                        This means in main.c the variable will be declared as an unsigned char.



                        Now in other files simply including global.h will
                        have it declared as an extern for that file.



                        extern unsigned char testing_mode;


                        But it will be correctly declared as an unsigned char.



                        The old forum post probably explained this a bit more clearly.
                        But this is a real potential gotcha when using a compiler
                        that allows you to declare a variable in one file and then declare it extern as a different type in another. The problems associated with
                        that are if you say declared testing_mode as an int in another file
                        it would think it was a 16 bit var and overwrite some other part of ram, potentially corrupting another variable. Difficult to debug!






                        share|improve this answer























                          protected by Lundin Aug 26 '15 at 14:18



                          Thank you for your interest in this question.
                          Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                          Would you like to answer one of these unanswered questions instead?













                          16 Answers
                          16






                          active

                          oldest

                          votes








                          16 Answers
                          16






                          active

                          oldest

                          votes









                          active

                          oldest

                          votes






                          active

                          oldest

                          votes









                          1583





                          +100









                          Using extern is only of relevance when the program you're building
                          consists of multiple source files linked together, where some of the
                          variables defined, for example, in source file file1.c need to be
                          referenced in other source files, such as file2.c.



                          It is important to understand the difference between defining a
                          variable and declaring a
                          variable:



                          • A variable is declared when the compiler is informed that a
                            variable exists (and this is its type); it does not allocate the
                            storage for the variable at that point.

                          • A variable is defined when the compiler allocates the storage for
                            the variable.

                          You may declare a variable multiple times (though once is sufficient);
                          you may only define it once within a given scope.
                          A variable definition is also a declaration, but not all variable
                          declarations are definitions.



                          Best way to declare and define global variables



                          The clean, reliable way to declare and define global variables is to use
                          a header file to contain an extern declaration of the variable.



                          The header is included by the one source file that defines the variable
                          and by all the source files that reference the variable.
                          For each program, one source file (and only one source file) defines the
                          variable.
                          Similarly, one header file (and only one header file) should declare the
                          variable.
                          The header file is crucial; it enables cross-checking between
                          independent TUs (translation units — think source files) and ensures
                          consistency.



                          Although there are other ways of doing it, this method is simple and
                          reliable.
                          It is demonstrated by file3.h, file1.c and file2.c:



                          file3.h



                          extern int global_variable; /* Declaration of the variable */


                          file1.c



                          #include "file3.h" /* Declaration made available here */
                          #include "prog1.h" /* Function declarations */

                          /* Variable defined here */
                          int global_variable = 37; /* Definition checked against declaration */

                          int increment(void) return global_variable++;


                          file2.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);



                          That's the best way to declare and define global variables.




                          The next two files complete the source for prog1:



                          The complete programs shown use functions, so function declarations have
                          crept in.
                          Both C99 and C11 require functions to be declared or defined before they
                          are used (whereas C90 did not, for good reasons).
                          I use the keyword extern in front of function declarations in headers
                          for consistency — to match the extern in front of variable
                          declarations in headers.
                          Many people prefer not to use extern in front of function
                          declarations; the compiler doesn't care — and ultimately, neither do I
                          as long as you're consistent, at least within a source file.



                          prog1.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog1.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog1 uses prog1.c, file1.c, file2.c, file3.h and prog1.h.

                          The file prog1.mk is a makefile for prog1 only.
                          It will work with most versions of make produced since about the turn
                          of the millennium.
                          It is not tied specifically to GNU Make.



                          prog1.mk



                          # Minimal makefile for prog1

                          PROGRAM = prog1
                          FILES.c = prog1.c file1.c file2.c
                          FILES.h = prog1.h file3.h
                          FILES.o = $FILES.c:.c=.o

                          CC = gcc
                          SFLAGS = -std=c11
                          GFLAGS = -g
                          OFLAGS = -O3
                          WFLAG1 = -Wall
                          WFLAG2 = -Wextra
                          WFLAG3 = -Werror
                          WFLAG4 = -Wstrict-prototypes
                          WFLAG5 = -Wmissing-prototypes
                          WFLAGS = $WFLAG1 $WFLAG2 $WFLAG3 $WFLAG4 $WFLAG5
                          UFLAGS = # Set on command line only

                          CFLAGS = $SFLAGS $GFLAGS $OFLAGS $WFLAGS $UFLAGS
                          LDFLAGS =
                          LDLIBS =

                          all: $PROGRAM

                          $PROGRAM: $FILES.o
                          $CC -o $@ $CFLAGS $FILES.o $LDFLAGS $LDLIBS

                          prog1.o: $FILES.h
                          file1.o: $FILES.h
                          file2.o: $FILES.h

                          # If it exists, prog1.dSYM is a directory on macOS
                          DEBRIS = a.out core *~ *.dSYM
                          RM_FR = rm -fr

                          clean:
                          $RM_FR $FILES.o $PROGRAM $DEBRIS



                          Guidelines



                          Rules to be broken by experts only, and only with good reason:



                          • A header file only contains extern declarations of variables — never
                            static or unqualified variable definitions.

                          • For any given variable, only one header file declares it (SPOT —
                            Single Point of Truth).

                          • A source file never contains extern declarations of variables —
                            source files always include the (sole) header that declares them.

                          • For any given variable, exactly one source file defines the variable,
                            preferably initializing it too. (Although there is no need to
                            initialize explicitly to zero, it does no harm and can do some good,
                            because there can be only one initialized definition of a particular
                            global variable in a program).

                          • The source file that defines the variable also includes the header to
                            ensure that the definition and the declaration are consistent.

                          • A function should never need to declare a variable using extern.

                          • Avoid global variables whenever possible — use functions instead.

                          The source code and text of this answer are available in my
                          SOQ (Stack Overflow Questions)
                          repository on GitHub in the
                          src/so-0143-3204
                          sub-directory.



                          If you're not an experienced C programmer, you could (and perhaps
                          should) stop reading here.



                          Not so good way to define global variables



                          With some (indeed, many) C compilers, you can get away with what's
                          called a 'common' definition of a variable too.
                          'Common', here, refers to a technique used in Fortran for sharing
                          variables between source files, using a (possibly named) COMMON block.
                          What happens here is that each of a number of files provides a tentative
                          definition of the variable.
                          As long as no more than one file provides an initialized definition,
                          then the various files end up sharing a common single definition of the
                          variable:



                          file10.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void inc(void) i++;


                          file11.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void dec(void) i--;


                          file12.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int i = 9; /* Do not do this in portable code */

                          void put(void) printf("i = %dn", i);


                          This technique does not conform to the letter of the C standard and the
                          'one definition rule' — it is officially undefined behaviour:




                          J.2 Undefined behavior



                          An identifier with external linkage is used, but in the program there
                          does not exist exactly one external definition for the identifier, or
                          the identifier is not used and there exist multiple external
                          definitions for the identifier (6.9).



                          §6.9 External definitions ¶5



                          An external definition is an external declaration that is also a
                          definition of a function (other than an inline definition) or an
                          object.
                          If an identifier declared with external linkage is used in an
                          expression (other than as part of the operand of a sizeof or
                          _Alignof operator whose result is an integer constant), somewhere in
                          the entire program there shall be exactly one external definition for
                          the identifier; otherwise, there shall be no more than
                          one.161)



                          161) Thus, if an identifier declared with external linkage
                          is not used in an expression, there need be no external definition for
                          it.




                          However, the C standard also lists it in informative Annex J as one of
                          the Common extensions.




                          J.5.11 Multiple external definitions



                          There may be more than one external definition for the identifier of
                          an object, with or without the explicit use of the keyword extern; if
                          the definitions disagree, or more than one is initialized, the
                          behavior is undefined (6.9.2).




                          Because this technique is not always supported, it is best to avoid
                          using it, especially if your code needs to be portable.
                          Using this technique, you can also end up with unintentional type
                          punning.
                          If one of the files declared i as a double instead of as an int,
                          C's type-unsafe linkers probably would not spot the mismatch.
                          If you're on a machine with 64-bit int and double, you'd not even
                          get a warning; on a machine with 32-bit int and 64-bit double, you'd
                          probably get a warning about the different sizes — the linker would
                          use the largest size, exactly as a Fortran program would take the
                          largest size of any common blocks.




                          The next two files complete the source for prog2:



                          prog2.h



                          extern void dec(void);
                          extern void put(void);
                          extern void inc(void);


                          prog2.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int main(void)

                          inc();
                          put();
                          dec();
                          put();
                          dec();
                          put();




                          • prog2 uses prog2.c, file10.c, file11.c, file12.c, prog2.h.


                          Warning



                          As noted in comments here, and as stated in my answer to a similar
                          question, using multiple
                          definitions for a global variable leads to undefined behaviour (J.2;
                          §6.9), which is the standard's way of saying "anything could happen".
                          One of the things that can happen is that the program behaves as you
                          expect; and J.5.11 says, approximately, "you might be lucky more often
                          than you deserve".
                          But a program that relies on multiple definitions of an extern variable
                          — with or without the explicit 'extern' keyword — is not a strictly
                          conforming program and not guaranteed to work everywhere.
                          Equivalently: it contains a bug which may or may not show itself.



                          Violating the guidelines



                          There are, of course, many ways in which these guidelines can be broken.
                          Occasionally, there may be a good reason to break the guidelines, but
                          such occasions are extremely unusual.



                          faulty_header.h



                          int some_var; /* Do not do this in a header!!! */


                          Note 1: if the header defines the variable without the extern keyword,
                          then each file that includes the header creates a tentative definition
                          of the variable.
                          As noted previously, this will often work, but the C standard does not
                          guarantee that it will work.



                          broken_header.h



                          int some_var = 13; /* Only one source file in a program can use this */


                          Note 2: if the header defines and initializes the variable, then only
                          one source file in a given program can use the header.
                          Since headers are primarily for sharing information, it is a bit silly
                          to create one that can only be used once.



                          seldom_correct.h



                          static int hidden_global = 3; /* Each source file gets its own copy */


                          Note 3: if the header defines a static variable (with or without
                          initialization), then each source file ends up with its own private
                          version of the 'global' variable.



                          If the variable is actually a complex array, for example, this can lead
                          to extreme duplication of code. It can, very occasionally, be a
                          sensible way to achieve some effect, but that is very unusual.




                          Summary



                          Use the header technique I showed first.
                          It works reliably and everywhere.
                          Note, in particular, that the header declaring the global_variable is
                          included in every file that uses it — including the one that defines it.
                          This ensures that everything is self-consistent.



                          Similar concerns arise with declaring and defining functions —
                          analogous rules apply.
                          But the question was about variables specifically, so I've kept the
                          answer to variables only.



                          End of Original Answer



                          If you're not an experienced C programmer, you probably should stop reading here.




                          Late Major Addition



                          Avoiding Code Duplication



                          One concern that is sometimes (and legitimately) raised about the
                          'declarations in headers, definitions in source' mechanism described
                          here is that there are two files to be kept synchronized — the header
                          and the source. This is usually followed up with an observation that a
                          macro can be used so that the header serves double duty — normally
                          declaring the variables, but when a specific macro is set before the
                          header is included, it defines the variables instead.



                          Another concern can be that the variables need to be defined in each of
                          a number of 'main programs'. This is normally a spurious concern; you
                          can simply introduce a C source file to define the variables and link
                          the object file produced with each of the programs.



                          A typical scheme works like this, using the original global variable
                          illustrated in file3.h:



                          file3a.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #else
                          #define EXTERN extern
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable;


                          file1a.c



                          #define DEFINE_VARIABLES
                          #include "file3a.h" /* Variable defined - but not initialized */
                          #include "prog3.h"

                          int increment(void) return global_variable++;


                          file2a.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);




                          The next two files complete the source for prog3:



                          prog3.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog3.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog3 uses prog3.c, file1a.c, file2a.c, file3a.h, prog3.h.


                          Variable initialization



                          The problem with this scheme as shown is that it does not provide for
                          initialization of the global variable. With C99 or C11 and variable argument
                          lists for macros, you could define a macro to support initialization too.
                          (With C89 and no support for variable argument lists in macros, there is no
                          easy way to handle arbitrarily long initializers.)



                          file3b.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZER(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZER(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable INITIALIZER(37);
                          EXTERN struct int a; int b; oddball_struct INITIALIZER( 41, 43 );


                          Reverse contents of #if and #else blocks, fixing bug identified by
                          Denis Kniazhev



                          file1b.c



                          #define DEFINE_VARIABLES
                          #include "file3b.h" /* Variables now defined and initialized */
                          #include "prog4.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file2b.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          Clearly, the code for the oddball structure is not what you'd normally
                          write, but it illustrates the point. The first argument to the second
                          invocation of INITIALIZER is 41 and the remaining argument
                          (singular in this example) is 43 . Without C99 or similar support
                          for variable argument lists for macros, initializers that need to
                          contain commas are very problematic.



                          Correct header file3b.h included (instead of fileba.h) per
                          Denis Kniazhev




                          The next two files complete the source for prog4:



                          prog4.h



                          extern int increment(void);
                          extern int oddball_value(void);
                          extern void use_them(void);


                          prog4.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog4 uses prog4.c, file1b.c, file2b.c, prog4.h, file3b.h.


                          Header Guards



                          Any header should be protected against reinclusion, so that type
                          definitions (enum, struct or union types, or typedefs generally) do not
                          cause problems. The standard technique is to wrap the body of the
                          header in a header guard such as:



                          #ifndef FILE3B_H_INCLUDED
                          #define FILE3B_H_INCLUDED

                          ...contents of header...

                          #endif /* FILE3B_H_INCLUDED */


                          The header might be included twice indirectly. For example, if
                          file4b.h includes file3b.h for a type definition that isn't shown,
                          and file1b.c needs to use both header file4b.h and file3b.h, then
                          you have some more tricky issues to resolve. Clearly, you might revise
                          the header list to include just file4b.h. However, you might not be
                          aware of the internal dependencies — and the code should, ideally,
                          continue to work.



                          Further, it starts to get tricky because you might include file4b.h
                          before including file3b.h to generate the definitions, but the normal
                          header guards on file3b.h would prevent the header being reincluded.



                          So, you need to include the body of file3b.h at most once for
                          declarations, and at most once for definitions, but you might need both
                          in a single translation unit (TU — a combination of a source file and
                          the headers it uses).



                          Multiple inclusion with variable definitions



                          However, it can be done subject to a not too unreasonable constraint.
                          Let's introduce a new set of file names:




                          • external.h for the EXTERN macro definitions, etc.


                          • file1c.h to define types (notably, struct oddball, the type of oddball_struct).


                          • file2c.h to define or declare the global variables.


                          • file3c.c which defines the global variables.


                          • file4c.c which simply uses the global variables.


                          • file5c.c which shows that you can declare and then define the global variables.


                          • file6c.c which shows that you can define and then (attempt to) declare the global variables.

                          In these examples, file5c.c and file6c.c directly include the header
                          file2c.h several times, but that is the simplest way to show that the
                          mechanism works. It means that if the header was indirectly included
                          twice, it would also be safe.



                          The restrictions for this to work are:



                          1. The header defining or declaring the global variables may not itself
                            define any types.

                          2. Immediately before you include a header that should define variables,
                            you define the macro DEFINE_VARIABLES.

                          3. The header defining or declaring the variables has stylized contents.

                          external.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is invoked, it redefines the macros EXTERN, INITIALIZE
                          ** based on whether macro DEFINE_VARIABLES is currently defined.
                          */
                          #undef EXTERN
                          #undef INITIALIZE

                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZE(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZE(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */


                          file1c.h



                          #ifndef FILE1C_H_INCLUDED
                          #define FILE1C_H_INCLUDED

                          struct oddball

                          int a;
                          int b;
                          ;

                          extern void use_them(void);
                          extern int increment(void);
                          extern int oddball_value(void);

                          #endif /* FILE1C_H_INCLUDED */


                          file2c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2C_H_DEFINITIONS)
                          #undef FILE2C_H_INCLUDED
                          #endif

                          #ifndef FILE2C_H_INCLUDED
                          #define FILE2C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2C_H_INCLUDED */


                          file3c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file4c.c



                          #include "file2c.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          file5c.c



                          #include "file2c.h" /* Declare variables */

                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file6c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          #include "file2c.h" /* Declare variables */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next source file completes the source (provides a main program) for prog5, prog6 and prog7:



                          prog5.c



                          #include "file2c.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog5 uses prog5.c, file3c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog6 uses prog5.c, file5c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog7 uses prog5.c, file6c.c, file4c.c, file1c.h, file2c.h, external.h.


                          This scheme avoids most problems. You only run into a problem if a
                          header that defines variables (such as file2c.h) is included by
                          another header (say file7c.h) that defines variables. There isn't an
                          easy way around that other than "don't do it".



                          You can partially work around the problem by revising file2c.h into
                          file2d.h:



                          file2d.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2D_H_DEFINITIONS)
                          #undef FILE2D_H_INCLUDED
                          #endif

                          #ifndef FILE2D_H_INCLUDED
                          #define FILE2D_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2D_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2D_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2D_H_DEFINITIONS
                          #undef DEFINE_VARIABLES
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2D_H_INCLUDED */


                          The issue becomes 'should the header include #undef DEFINE_VARIABLES?'
                          If you omit that from the header and wrap any defining invocation with
                          #define and #undef:



                          #define DEFINE_VARIABLES
                          #include "file2c.h"
                          #undef DEFINE_VARIABLES


                          in the source code (so the headers never alter the value of
                          DEFINE_VARIABLES), then you should be clean. It is just a nuisance to
                          have to remember to write the the extra line. An alternative might be:



                          #define HEADER_DEFINING_VARIABLES "file2c.h"
                          #include "externdef.h"


                          externdef.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is included, the macro HEADER_DEFINING_VARIABLES should
                          ** be defined with the name (in quotes - or possibly angle brackets) of
                          ** the header to be included that defines variables when the macro
                          ** DEFINE_VARIABLES is defined. See also: external.h (which uses
                          ** DEFINE_VARIABLES and defines macros EXTERN and INITIALIZE
                          ** appropriately).
                          **
                          ** #define HEADER_DEFINING_VARIABLES "file2c.h"
                          ** #include "externdef.h"
                          */

                          #if defined(HEADER_DEFINING_VARIABLES)
                          #define DEFINE_VARIABLES
                          #include HEADER_DEFINING_VARIABLES
                          #undef DEFINE_VARIABLES
                          #undef HEADER_DEFINING_VARIABLES
                          #endif /* HEADER_DEFINING_VARIABLES */


                          This is getting a tad convoluted, but seems to be secure (using the
                          file2d.h, with no #undef DEFINE_VARIABLES in the file2d.h).



                          file7c.c



                          /* Declare variables */
                          #include "file2d.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Declare variables - again */
                          #include "file2d.h"

                          /* Define variables - again */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file8c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE8C_H_DEFINITIONS)
                          #undef FILE8C_H_INCLUDED
                          #endif

                          #ifndef FILE8C_H_INCLUDED
                          #define FILE8C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file2d.h" /* struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE8C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN struct oddball another INITIALIZE( 14, 34 );

                          #endif /* !DEFINE_VARIABLES || !FILE8C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE8C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE8C_H_INCLUDED */


                          file8c.c



                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file8c.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next two files complete the source for prog8 and prog9:



                          prog8.c



                          #include "file2d.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;



                          file9c.c



                          #include "file2d.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;




                          • prog8 uses prog8.c, file7c.c, file9c.c.


                          • prog9 uses prog8.c, file8c.c, file9c.c.


                          However, the problems are relatively unlikely to occur in practice,
                          especially if you take the standard advice to



                          Avoid global variables




                          Does this exposition miss anything?



                          Confession: The 'avoiding duplicated code' scheme outlined here was
                          developed because the issue affects some code I work on (but don't own),
                          and is a niggling concern with the scheme outlined in the first part of
                          the answer. However, the original scheme leaves you with just two
                          places to modify to keep variable definitions and declarations
                          synchronized, which is a big step forward over having exernal variable
                          declarations scattered throughout the code base (which really matters
                          when there are thousands of files in total). However, the code in the
                          files with the names fileNc.[ch] (plus external.h and externdef.h)
                          shows that it can be made to work. Clearly, it would not be hard to
                          create a header generator script to give you the standardized template
                          for a variable defining and declaring header file.



                          NB These are toy programs with just barely enough code to make them
                          marginally interesting. There is repetition within the examples that
                          could be removed, but isn't to simplify the pedagogical explanation.
                          (For example: the difference between prog5.c and prog8.c is the name
                          of one of the headers that are included. It would be possible to
                          reorganize the code so that the main() function was not repeated, but
                          it would conceal more than it revealed.)






                          share|improve this answer




















                          • 3





                            @litb: see Annex J.5.11 for the common definition - it is a common extension.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:19






                          • 3





                            @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:20






                          • 3





                            Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

                            – Johannes Schaub - litb
                            Sep 16 '09 at 15:30






                          • 3





                            @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

                            – Jonathan Leffler
                            Jan 16 '13 at 2:14






                          • 11





                            If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

                            – Jonathan Leffler
                            Aug 5 '14 at 3:28















                          1583





                          +100









                          Using extern is only of relevance when the program you're building
                          consists of multiple source files linked together, where some of the
                          variables defined, for example, in source file file1.c need to be
                          referenced in other source files, such as file2.c.



                          It is important to understand the difference between defining a
                          variable and declaring a
                          variable:



                          • A variable is declared when the compiler is informed that a
                            variable exists (and this is its type); it does not allocate the
                            storage for the variable at that point.

                          • A variable is defined when the compiler allocates the storage for
                            the variable.

                          You may declare a variable multiple times (though once is sufficient);
                          you may only define it once within a given scope.
                          A variable definition is also a declaration, but not all variable
                          declarations are definitions.



                          Best way to declare and define global variables



                          The clean, reliable way to declare and define global variables is to use
                          a header file to contain an extern declaration of the variable.



                          The header is included by the one source file that defines the variable
                          and by all the source files that reference the variable.
                          For each program, one source file (and only one source file) defines the
                          variable.
                          Similarly, one header file (and only one header file) should declare the
                          variable.
                          The header file is crucial; it enables cross-checking between
                          independent TUs (translation units — think source files) and ensures
                          consistency.



                          Although there are other ways of doing it, this method is simple and
                          reliable.
                          It is demonstrated by file3.h, file1.c and file2.c:



                          file3.h



                          extern int global_variable; /* Declaration of the variable */


                          file1.c



                          #include "file3.h" /* Declaration made available here */
                          #include "prog1.h" /* Function declarations */

                          /* Variable defined here */
                          int global_variable = 37; /* Definition checked against declaration */

                          int increment(void) return global_variable++;


                          file2.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);



                          That's the best way to declare and define global variables.




                          The next two files complete the source for prog1:



                          The complete programs shown use functions, so function declarations have
                          crept in.
                          Both C99 and C11 require functions to be declared or defined before they
                          are used (whereas C90 did not, for good reasons).
                          I use the keyword extern in front of function declarations in headers
                          for consistency — to match the extern in front of variable
                          declarations in headers.
                          Many people prefer not to use extern in front of function
                          declarations; the compiler doesn't care — and ultimately, neither do I
                          as long as you're consistent, at least within a source file.



                          prog1.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog1.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog1 uses prog1.c, file1.c, file2.c, file3.h and prog1.h.

                          The file prog1.mk is a makefile for prog1 only.
                          It will work with most versions of make produced since about the turn
                          of the millennium.
                          It is not tied specifically to GNU Make.



                          prog1.mk



                          # Minimal makefile for prog1

                          PROGRAM = prog1
                          FILES.c = prog1.c file1.c file2.c
                          FILES.h = prog1.h file3.h
                          FILES.o = $FILES.c:.c=.o

                          CC = gcc
                          SFLAGS = -std=c11
                          GFLAGS = -g
                          OFLAGS = -O3
                          WFLAG1 = -Wall
                          WFLAG2 = -Wextra
                          WFLAG3 = -Werror
                          WFLAG4 = -Wstrict-prototypes
                          WFLAG5 = -Wmissing-prototypes
                          WFLAGS = $WFLAG1 $WFLAG2 $WFLAG3 $WFLAG4 $WFLAG5
                          UFLAGS = # Set on command line only

                          CFLAGS = $SFLAGS $GFLAGS $OFLAGS $WFLAGS $UFLAGS
                          LDFLAGS =
                          LDLIBS =

                          all: $PROGRAM

                          $PROGRAM: $FILES.o
                          $CC -o $@ $CFLAGS $FILES.o $LDFLAGS $LDLIBS

                          prog1.o: $FILES.h
                          file1.o: $FILES.h
                          file2.o: $FILES.h

                          # If it exists, prog1.dSYM is a directory on macOS
                          DEBRIS = a.out core *~ *.dSYM
                          RM_FR = rm -fr

                          clean:
                          $RM_FR $FILES.o $PROGRAM $DEBRIS



                          Guidelines



                          Rules to be broken by experts only, and only with good reason:



                          • A header file only contains extern declarations of variables — never
                            static or unqualified variable definitions.

                          • For any given variable, only one header file declares it (SPOT —
                            Single Point of Truth).

                          • A source file never contains extern declarations of variables —
                            source files always include the (sole) header that declares them.

                          • For any given variable, exactly one source file defines the variable,
                            preferably initializing it too. (Although there is no need to
                            initialize explicitly to zero, it does no harm and can do some good,
                            because there can be only one initialized definition of a particular
                            global variable in a program).

                          • The source file that defines the variable also includes the header to
                            ensure that the definition and the declaration are consistent.

                          • A function should never need to declare a variable using extern.

                          • Avoid global variables whenever possible — use functions instead.

                          The source code and text of this answer are available in my
                          SOQ (Stack Overflow Questions)
                          repository on GitHub in the
                          src/so-0143-3204
                          sub-directory.



                          If you're not an experienced C programmer, you could (and perhaps
                          should) stop reading here.



                          Not so good way to define global variables



                          With some (indeed, many) C compilers, you can get away with what's
                          called a 'common' definition of a variable too.
                          'Common', here, refers to a technique used in Fortran for sharing
                          variables between source files, using a (possibly named) COMMON block.
                          What happens here is that each of a number of files provides a tentative
                          definition of the variable.
                          As long as no more than one file provides an initialized definition,
                          then the various files end up sharing a common single definition of the
                          variable:



                          file10.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void inc(void) i++;


                          file11.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void dec(void) i--;


                          file12.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int i = 9; /* Do not do this in portable code */

                          void put(void) printf("i = %dn", i);


                          This technique does not conform to the letter of the C standard and the
                          'one definition rule' — it is officially undefined behaviour:




                          J.2 Undefined behavior



                          An identifier with external linkage is used, but in the program there
                          does not exist exactly one external definition for the identifier, or
                          the identifier is not used and there exist multiple external
                          definitions for the identifier (6.9).



                          §6.9 External definitions ¶5



                          An external definition is an external declaration that is also a
                          definition of a function (other than an inline definition) or an
                          object.
                          If an identifier declared with external linkage is used in an
                          expression (other than as part of the operand of a sizeof or
                          _Alignof operator whose result is an integer constant), somewhere in
                          the entire program there shall be exactly one external definition for
                          the identifier; otherwise, there shall be no more than
                          one.161)



                          161) Thus, if an identifier declared with external linkage
                          is not used in an expression, there need be no external definition for
                          it.




                          However, the C standard also lists it in informative Annex J as one of
                          the Common extensions.




                          J.5.11 Multiple external definitions



                          There may be more than one external definition for the identifier of
                          an object, with or without the explicit use of the keyword extern; if
                          the definitions disagree, or more than one is initialized, the
                          behavior is undefined (6.9.2).




                          Because this technique is not always supported, it is best to avoid
                          using it, especially if your code needs to be portable.
                          Using this technique, you can also end up with unintentional type
                          punning.
                          If one of the files declared i as a double instead of as an int,
                          C's type-unsafe linkers probably would not spot the mismatch.
                          If you're on a machine with 64-bit int and double, you'd not even
                          get a warning; on a machine with 32-bit int and 64-bit double, you'd
                          probably get a warning about the different sizes — the linker would
                          use the largest size, exactly as a Fortran program would take the
                          largest size of any common blocks.




                          The next two files complete the source for prog2:



                          prog2.h



                          extern void dec(void);
                          extern void put(void);
                          extern void inc(void);


                          prog2.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int main(void)

                          inc();
                          put();
                          dec();
                          put();
                          dec();
                          put();




                          • prog2 uses prog2.c, file10.c, file11.c, file12.c, prog2.h.


                          Warning



                          As noted in comments here, and as stated in my answer to a similar
                          question, using multiple
                          definitions for a global variable leads to undefined behaviour (J.2;
                          §6.9), which is the standard's way of saying "anything could happen".
                          One of the things that can happen is that the program behaves as you
                          expect; and J.5.11 says, approximately, "you might be lucky more often
                          than you deserve".
                          But a program that relies on multiple definitions of an extern variable
                          — with or without the explicit 'extern' keyword — is not a strictly
                          conforming program and not guaranteed to work everywhere.
                          Equivalently: it contains a bug which may or may not show itself.



                          Violating the guidelines



                          There are, of course, many ways in which these guidelines can be broken.
                          Occasionally, there may be a good reason to break the guidelines, but
                          such occasions are extremely unusual.



                          faulty_header.h



                          int some_var; /* Do not do this in a header!!! */


                          Note 1: if the header defines the variable without the extern keyword,
                          then each file that includes the header creates a tentative definition
                          of the variable.
                          As noted previously, this will often work, but the C standard does not
                          guarantee that it will work.



                          broken_header.h



                          int some_var = 13; /* Only one source file in a program can use this */


                          Note 2: if the header defines and initializes the variable, then only
                          one source file in a given program can use the header.
                          Since headers are primarily for sharing information, it is a bit silly
                          to create one that can only be used once.



                          seldom_correct.h



                          static int hidden_global = 3; /* Each source file gets its own copy */


                          Note 3: if the header defines a static variable (with or without
                          initialization), then each source file ends up with its own private
                          version of the 'global' variable.



                          If the variable is actually a complex array, for example, this can lead
                          to extreme duplication of code. It can, very occasionally, be a
                          sensible way to achieve some effect, but that is very unusual.




                          Summary



                          Use the header technique I showed first.
                          It works reliably and everywhere.
                          Note, in particular, that the header declaring the global_variable is
                          included in every file that uses it — including the one that defines it.
                          This ensures that everything is self-consistent.



                          Similar concerns arise with declaring and defining functions —
                          analogous rules apply.
                          But the question was about variables specifically, so I've kept the
                          answer to variables only.



                          End of Original Answer



                          If you're not an experienced C programmer, you probably should stop reading here.




                          Late Major Addition



                          Avoiding Code Duplication



                          One concern that is sometimes (and legitimately) raised about the
                          'declarations in headers, definitions in source' mechanism described
                          here is that there are two files to be kept synchronized — the header
                          and the source. This is usually followed up with an observation that a
                          macro can be used so that the header serves double duty — normally
                          declaring the variables, but when a specific macro is set before the
                          header is included, it defines the variables instead.



                          Another concern can be that the variables need to be defined in each of
                          a number of 'main programs'. This is normally a spurious concern; you
                          can simply introduce a C source file to define the variables and link
                          the object file produced with each of the programs.



                          A typical scheme works like this, using the original global variable
                          illustrated in file3.h:



                          file3a.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #else
                          #define EXTERN extern
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable;


                          file1a.c



                          #define DEFINE_VARIABLES
                          #include "file3a.h" /* Variable defined - but not initialized */
                          #include "prog3.h"

                          int increment(void) return global_variable++;


                          file2a.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);




                          The next two files complete the source for prog3:



                          prog3.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog3.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog3 uses prog3.c, file1a.c, file2a.c, file3a.h, prog3.h.


                          Variable initialization



                          The problem with this scheme as shown is that it does not provide for
                          initialization of the global variable. With C99 or C11 and variable argument
                          lists for macros, you could define a macro to support initialization too.
                          (With C89 and no support for variable argument lists in macros, there is no
                          easy way to handle arbitrarily long initializers.)



                          file3b.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZER(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZER(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable INITIALIZER(37);
                          EXTERN struct int a; int b; oddball_struct INITIALIZER( 41, 43 );


                          Reverse contents of #if and #else blocks, fixing bug identified by
                          Denis Kniazhev



                          file1b.c



                          #define DEFINE_VARIABLES
                          #include "file3b.h" /* Variables now defined and initialized */
                          #include "prog4.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file2b.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          Clearly, the code for the oddball structure is not what you'd normally
                          write, but it illustrates the point. The first argument to the second
                          invocation of INITIALIZER is 41 and the remaining argument
                          (singular in this example) is 43 . Without C99 or similar support
                          for variable argument lists for macros, initializers that need to
                          contain commas are very problematic.



                          Correct header file3b.h included (instead of fileba.h) per
                          Denis Kniazhev




                          The next two files complete the source for prog4:



                          prog4.h



                          extern int increment(void);
                          extern int oddball_value(void);
                          extern void use_them(void);


                          prog4.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog4 uses prog4.c, file1b.c, file2b.c, prog4.h, file3b.h.


                          Header Guards



                          Any header should be protected against reinclusion, so that type
                          definitions (enum, struct or union types, or typedefs generally) do not
                          cause problems. The standard technique is to wrap the body of the
                          header in a header guard such as:



                          #ifndef FILE3B_H_INCLUDED
                          #define FILE3B_H_INCLUDED

                          ...contents of header...

                          #endif /* FILE3B_H_INCLUDED */


                          The header might be included twice indirectly. For example, if
                          file4b.h includes file3b.h for a type definition that isn't shown,
                          and file1b.c needs to use both header file4b.h and file3b.h, then
                          you have some more tricky issues to resolve. Clearly, you might revise
                          the header list to include just file4b.h. However, you might not be
                          aware of the internal dependencies — and the code should, ideally,
                          continue to work.



                          Further, it starts to get tricky because you might include file4b.h
                          before including file3b.h to generate the definitions, but the normal
                          header guards on file3b.h would prevent the header being reincluded.



                          So, you need to include the body of file3b.h at most once for
                          declarations, and at most once for definitions, but you might need both
                          in a single translation unit (TU — a combination of a source file and
                          the headers it uses).



                          Multiple inclusion with variable definitions



                          However, it can be done subject to a not too unreasonable constraint.
                          Let's introduce a new set of file names:




                          • external.h for the EXTERN macro definitions, etc.


                          • file1c.h to define types (notably, struct oddball, the type of oddball_struct).


                          • file2c.h to define or declare the global variables.


                          • file3c.c which defines the global variables.


                          • file4c.c which simply uses the global variables.


                          • file5c.c which shows that you can declare and then define the global variables.


                          • file6c.c which shows that you can define and then (attempt to) declare the global variables.

                          In these examples, file5c.c and file6c.c directly include the header
                          file2c.h several times, but that is the simplest way to show that the
                          mechanism works. It means that if the header was indirectly included
                          twice, it would also be safe.



                          The restrictions for this to work are:



                          1. The header defining or declaring the global variables may not itself
                            define any types.

                          2. Immediately before you include a header that should define variables,
                            you define the macro DEFINE_VARIABLES.

                          3. The header defining or declaring the variables has stylized contents.

                          external.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is invoked, it redefines the macros EXTERN, INITIALIZE
                          ** based on whether macro DEFINE_VARIABLES is currently defined.
                          */
                          #undef EXTERN
                          #undef INITIALIZE

                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZE(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZE(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */


                          file1c.h



                          #ifndef FILE1C_H_INCLUDED
                          #define FILE1C_H_INCLUDED

                          struct oddball

                          int a;
                          int b;
                          ;

                          extern void use_them(void);
                          extern int increment(void);
                          extern int oddball_value(void);

                          #endif /* FILE1C_H_INCLUDED */


                          file2c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2C_H_DEFINITIONS)
                          #undef FILE2C_H_INCLUDED
                          #endif

                          #ifndef FILE2C_H_INCLUDED
                          #define FILE2C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2C_H_INCLUDED */


                          file3c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file4c.c



                          #include "file2c.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          file5c.c



                          #include "file2c.h" /* Declare variables */

                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file6c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          #include "file2c.h" /* Declare variables */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next source file completes the source (provides a main program) for prog5, prog6 and prog7:



                          prog5.c



                          #include "file2c.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog5 uses prog5.c, file3c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog6 uses prog5.c, file5c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog7 uses prog5.c, file6c.c, file4c.c, file1c.h, file2c.h, external.h.


                          This scheme avoids most problems. You only run into a problem if a
                          header that defines variables (such as file2c.h) is included by
                          another header (say file7c.h) that defines variables. There isn't an
                          easy way around that other than "don't do it".



                          You can partially work around the problem by revising file2c.h into
                          file2d.h:



                          file2d.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2D_H_DEFINITIONS)
                          #undef FILE2D_H_INCLUDED
                          #endif

                          #ifndef FILE2D_H_INCLUDED
                          #define FILE2D_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2D_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2D_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2D_H_DEFINITIONS
                          #undef DEFINE_VARIABLES
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2D_H_INCLUDED */


                          The issue becomes 'should the header include #undef DEFINE_VARIABLES?'
                          If you omit that from the header and wrap any defining invocation with
                          #define and #undef:



                          #define DEFINE_VARIABLES
                          #include "file2c.h"
                          #undef DEFINE_VARIABLES


                          in the source code (so the headers never alter the value of
                          DEFINE_VARIABLES), then you should be clean. It is just a nuisance to
                          have to remember to write the the extra line. An alternative might be:



                          #define HEADER_DEFINING_VARIABLES "file2c.h"
                          #include "externdef.h"


                          externdef.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is included, the macro HEADER_DEFINING_VARIABLES should
                          ** be defined with the name (in quotes - or possibly angle brackets) of
                          ** the header to be included that defines variables when the macro
                          ** DEFINE_VARIABLES is defined. See also: external.h (which uses
                          ** DEFINE_VARIABLES and defines macros EXTERN and INITIALIZE
                          ** appropriately).
                          **
                          ** #define HEADER_DEFINING_VARIABLES "file2c.h"
                          ** #include "externdef.h"
                          */

                          #if defined(HEADER_DEFINING_VARIABLES)
                          #define DEFINE_VARIABLES
                          #include HEADER_DEFINING_VARIABLES
                          #undef DEFINE_VARIABLES
                          #undef HEADER_DEFINING_VARIABLES
                          #endif /* HEADER_DEFINING_VARIABLES */


                          This is getting a tad convoluted, but seems to be secure (using the
                          file2d.h, with no #undef DEFINE_VARIABLES in the file2d.h).



                          file7c.c



                          /* Declare variables */
                          #include "file2d.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Declare variables - again */
                          #include "file2d.h"

                          /* Define variables - again */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file8c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE8C_H_DEFINITIONS)
                          #undef FILE8C_H_INCLUDED
                          #endif

                          #ifndef FILE8C_H_INCLUDED
                          #define FILE8C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file2d.h" /* struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE8C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN struct oddball another INITIALIZE( 14, 34 );

                          #endif /* !DEFINE_VARIABLES || !FILE8C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE8C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE8C_H_INCLUDED */


                          file8c.c



                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file8c.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next two files complete the source for prog8 and prog9:



                          prog8.c



                          #include "file2d.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;



                          file9c.c



                          #include "file2d.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;




                          • prog8 uses prog8.c, file7c.c, file9c.c.


                          • prog9 uses prog8.c, file8c.c, file9c.c.


                          However, the problems are relatively unlikely to occur in practice,
                          especially if you take the standard advice to



                          Avoid global variables




                          Does this exposition miss anything?



                          Confession: The 'avoiding duplicated code' scheme outlined here was
                          developed because the issue affects some code I work on (but don't own),
                          and is a niggling concern with the scheme outlined in the first part of
                          the answer. However, the original scheme leaves you with just two
                          places to modify to keep variable definitions and declarations
                          synchronized, which is a big step forward over having exernal variable
                          declarations scattered throughout the code base (which really matters
                          when there are thousands of files in total). However, the code in the
                          files with the names fileNc.[ch] (plus external.h and externdef.h)
                          shows that it can be made to work. Clearly, it would not be hard to
                          create a header generator script to give you the standardized template
                          for a variable defining and declaring header file.



                          NB These are toy programs with just barely enough code to make them
                          marginally interesting. There is repetition within the examples that
                          could be removed, but isn't to simplify the pedagogical explanation.
                          (For example: the difference between prog5.c and prog8.c is the name
                          of one of the headers that are included. It would be possible to
                          reorganize the code so that the main() function was not repeated, but
                          it would conceal more than it revealed.)






                          share|improve this answer




















                          • 3





                            @litb: see Annex J.5.11 for the common definition - it is a common extension.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:19






                          • 3





                            @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:20






                          • 3





                            Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

                            – Johannes Schaub - litb
                            Sep 16 '09 at 15:30






                          • 3





                            @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

                            – Jonathan Leffler
                            Jan 16 '13 at 2:14






                          • 11





                            If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

                            – Jonathan Leffler
                            Aug 5 '14 at 3:28













                          1583





                          +100







                          1583





                          +100



                          1583




                          +100





                          Using extern is only of relevance when the program you're building
                          consists of multiple source files linked together, where some of the
                          variables defined, for example, in source file file1.c need to be
                          referenced in other source files, such as file2.c.



                          It is important to understand the difference between defining a
                          variable and declaring a
                          variable:



                          • A variable is declared when the compiler is informed that a
                            variable exists (and this is its type); it does not allocate the
                            storage for the variable at that point.

                          • A variable is defined when the compiler allocates the storage for
                            the variable.

                          You may declare a variable multiple times (though once is sufficient);
                          you may only define it once within a given scope.
                          A variable definition is also a declaration, but not all variable
                          declarations are definitions.



                          Best way to declare and define global variables



                          The clean, reliable way to declare and define global variables is to use
                          a header file to contain an extern declaration of the variable.



                          The header is included by the one source file that defines the variable
                          and by all the source files that reference the variable.
                          For each program, one source file (and only one source file) defines the
                          variable.
                          Similarly, one header file (and only one header file) should declare the
                          variable.
                          The header file is crucial; it enables cross-checking between
                          independent TUs (translation units — think source files) and ensures
                          consistency.



                          Although there are other ways of doing it, this method is simple and
                          reliable.
                          It is demonstrated by file3.h, file1.c and file2.c:



                          file3.h



                          extern int global_variable; /* Declaration of the variable */


                          file1.c



                          #include "file3.h" /* Declaration made available here */
                          #include "prog1.h" /* Function declarations */

                          /* Variable defined here */
                          int global_variable = 37; /* Definition checked against declaration */

                          int increment(void) return global_variable++;


                          file2.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);



                          That's the best way to declare and define global variables.




                          The next two files complete the source for prog1:



                          The complete programs shown use functions, so function declarations have
                          crept in.
                          Both C99 and C11 require functions to be declared or defined before they
                          are used (whereas C90 did not, for good reasons).
                          I use the keyword extern in front of function declarations in headers
                          for consistency — to match the extern in front of variable
                          declarations in headers.
                          Many people prefer not to use extern in front of function
                          declarations; the compiler doesn't care — and ultimately, neither do I
                          as long as you're consistent, at least within a source file.



                          prog1.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog1.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog1 uses prog1.c, file1.c, file2.c, file3.h and prog1.h.

                          The file prog1.mk is a makefile for prog1 only.
                          It will work with most versions of make produced since about the turn
                          of the millennium.
                          It is not tied specifically to GNU Make.



                          prog1.mk



                          # Minimal makefile for prog1

                          PROGRAM = prog1
                          FILES.c = prog1.c file1.c file2.c
                          FILES.h = prog1.h file3.h
                          FILES.o = $FILES.c:.c=.o

                          CC = gcc
                          SFLAGS = -std=c11
                          GFLAGS = -g
                          OFLAGS = -O3
                          WFLAG1 = -Wall
                          WFLAG2 = -Wextra
                          WFLAG3 = -Werror
                          WFLAG4 = -Wstrict-prototypes
                          WFLAG5 = -Wmissing-prototypes
                          WFLAGS = $WFLAG1 $WFLAG2 $WFLAG3 $WFLAG4 $WFLAG5
                          UFLAGS = # Set on command line only

                          CFLAGS = $SFLAGS $GFLAGS $OFLAGS $WFLAGS $UFLAGS
                          LDFLAGS =
                          LDLIBS =

                          all: $PROGRAM

                          $PROGRAM: $FILES.o
                          $CC -o $@ $CFLAGS $FILES.o $LDFLAGS $LDLIBS

                          prog1.o: $FILES.h
                          file1.o: $FILES.h
                          file2.o: $FILES.h

                          # If it exists, prog1.dSYM is a directory on macOS
                          DEBRIS = a.out core *~ *.dSYM
                          RM_FR = rm -fr

                          clean:
                          $RM_FR $FILES.o $PROGRAM $DEBRIS



                          Guidelines



                          Rules to be broken by experts only, and only with good reason:



                          • A header file only contains extern declarations of variables — never
                            static or unqualified variable definitions.

                          • For any given variable, only one header file declares it (SPOT —
                            Single Point of Truth).

                          • A source file never contains extern declarations of variables —
                            source files always include the (sole) header that declares them.

                          • For any given variable, exactly one source file defines the variable,
                            preferably initializing it too. (Although there is no need to
                            initialize explicitly to zero, it does no harm and can do some good,
                            because there can be only one initialized definition of a particular
                            global variable in a program).

                          • The source file that defines the variable also includes the header to
                            ensure that the definition and the declaration are consistent.

                          • A function should never need to declare a variable using extern.

                          • Avoid global variables whenever possible — use functions instead.

                          The source code and text of this answer are available in my
                          SOQ (Stack Overflow Questions)
                          repository on GitHub in the
                          src/so-0143-3204
                          sub-directory.



                          If you're not an experienced C programmer, you could (and perhaps
                          should) stop reading here.



                          Not so good way to define global variables



                          With some (indeed, many) C compilers, you can get away with what's
                          called a 'common' definition of a variable too.
                          'Common', here, refers to a technique used in Fortran for sharing
                          variables between source files, using a (possibly named) COMMON block.
                          What happens here is that each of a number of files provides a tentative
                          definition of the variable.
                          As long as no more than one file provides an initialized definition,
                          then the various files end up sharing a common single definition of the
                          variable:



                          file10.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void inc(void) i++;


                          file11.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void dec(void) i--;


                          file12.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int i = 9; /* Do not do this in portable code */

                          void put(void) printf("i = %dn", i);


                          This technique does not conform to the letter of the C standard and the
                          'one definition rule' — it is officially undefined behaviour:




                          J.2 Undefined behavior



                          An identifier with external linkage is used, but in the program there
                          does not exist exactly one external definition for the identifier, or
                          the identifier is not used and there exist multiple external
                          definitions for the identifier (6.9).



                          §6.9 External definitions ¶5



                          An external definition is an external declaration that is also a
                          definition of a function (other than an inline definition) or an
                          object.
                          If an identifier declared with external linkage is used in an
                          expression (other than as part of the operand of a sizeof or
                          _Alignof operator whose result is an integer constant), somewhere in
                          the entire program there shall be exactly one external definition for
                          the identifier; otherwise, there shall be no more than
                          one.161)



                          161) Thus, if an identifier declared with external linkage
                          is not used in an expression, there need be no external definition for
                          it.




                          However, the C standard also lists it in informative Annex J as one of
                          the Common extensions.




                          J.5.11 Multiple external definitions



                          There may be more than one external definition for the identifier of
                          an object, with or without the explicit use of the keyword extern; if
                          the definitions disagree, or more than one is initialized, the
                          behavior is undefined (6.9.2).




                          Because this technique is not always supported, it is best to avoid
                          using it, especially if your code needs to be portable.
                          Using this technique, you can also end up with unintentional type
                          punning.
                          If one of the files declared i as a double instead of as an int,
                          C's type-unsafe linkers probably would not spot the mismatch.
                          If you're on a machine with 64-bit int and double, you'd not even
                          get a warning; on a machine with 32-bit int and 64-bit double, you'd
                          probably get a warning about the different sizes — the linker would
                          use the largest size, exactly as a Fortran program would take the
                          largest size of any common blocks.




                          The next two files complete the source for prog2:



                          prog2.h



                          extern void dec(void);
                          extern void put(void);
                          extern void inc(void);


                          prog2.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int main(void)

                          inc();
                          put();
                          dec();
                          put();
                          dec();
                          put();




                          • prog2 uses prog2.c, file10.c, file11.c, file12.c, prog2.h.


                          Warning



                          As noted in comments here, and as stated in my answer to a similar
                          question, using multiple
                          definitions for a global variable leads to undefined behaviour (J.2;
                          §6.9), which is the standard's way of saying "anything could happen".
                          One of the things that can happen is that the program behaves as you
                          expect; and J.5.11 says, approximately, "you might be lucky more often
                          than you deserve".
                          But a program that relies on multiple definitions of an extern variable
                          — with or without the explicit 'extern' keyword — is not a strictly
                          conforming program and not guaranteed to work everywhere.
                          Equivalently: it contains a bug which may or may not show itself.



                          Violating the guidelines



                          There are, of course, many ways in which these guidelines can be broken.
                          Occasionally, there may be a good reason to break the guidelines, but
                          such occasions are extremely unusual.



                          faulty_header.h



                          int some_var; /* Do not do this in a header!!! */


                          Note 1: if the header defines the variable without the extern keyword,
                          then each file that includes the header creates a tentative definition
                          of the variable.
                          As noted previously, this will often work, but the C standard does not
                          guarantee that it will work.



                          broken_header.h



                          int some_var = 13; /* Only one source file in a program can use this */


                          Note 2: if the header defines and initializes the variable, then only
                          one source file in a given program can use the header.
                          Since headers are primarily for sharing information, it is a bit silly
                          to create one that can only be used once.



                          seldom_correct.h



                          static int hidden_global = 3; /* Each source file gets its own copy */


                          Note 3: if the header defines a static variable (with or without
                          initialization), then each source file ends up with its own private
                          version of the 'global' variable.



                          If the variable is actually a complex array, for example, this can lead
                          to extreme duplication of code. It can, very occasionally, be a
                          sensible way to achieve some effect, but that is very unusual.




                          Summary



                          Use the header technique I showed first.
                          It works reliably and everywhere.
                          Note, in particular, that the header declaring the global_variable is
                          included in every file that uses it — including the one that defines it.
                          This ensures that everything is self-consistent.



                          Similar concerns arise with declaring and defining functions —
                          analogous rules apply.
                          But the question was about variables specifically, so I've kept the
                          answer to variables only.



                          End of Original Answer



                          If you're not an experienced C programmer, you probably should stop reading here.




                          Late Major Addition



                          Avoiding Code Duplication



                          One concern that is sometimes (and legitimately) raised about the
                          'declarations in headers, definitions in source' mechanism described
                          here is that there are two files to be kept synchronized — the header
                          and the source. This is usually followed up with an observation that a
                          macro can be used so that the header serves double duty — normally
                          declaring the variables, but when a specific macro is set before the
                          header is included, it defines the variables instead.



                          Another concern can be that the variables need to be defined in each of
                          a number of 'main programs'. This is normally a spurious concern; you
                          can simply introduce a C source file to define the variables and link
                          the object file produced with each of the programs.



                          A typical scheme works like this, using the original global variable
                          illustrated in file3.h:



                          file3a.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #else
                          #define EXTERN extern
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable;


                          file1a.c



                          #define DEFINE_VARIABLES
                          #include "file3a.h" /* Variable defined - but not initialized */
                          #include "prog3.h"

                          int increment(void) return global_variable++;


                          file2a.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);




                          The next two files complete the source for prog3:



                          prog3.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog3.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog3 uses prog3.c, file1a.c, file2a.c, file3a.h, prog3.h.


                          Variable initialization



                          The problem with this scheme as shown is that it does not provide for
                          initialization of the global variable. With C99 or C11 and variable argument
                          lists for macros, you could define a macro to support initialization too.
                          (With C89 and no support for variable argument lists in macros, there is no
                          easy way to handle arbitrarily long initializers.)



                          file3b.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZER(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZER(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable INITIALIZER(37);
                          EXTERN struct int a; int b; oddball_struct INITIALIZER( 41, 43 );


                          Reverse contents of #if and #else blocks, fixing bug identified by
                          Denis Kniazhev



                          file1b.c



                          #define DEFINE_VARIABLES
                          #include "file3b.h" /* Variables now defined and initialized */
                          #include "prog4.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file2b.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          Clearly, the code for the oddball structure is not what you'd normally
                          write, but it illustrates the point. The first argument to the second
                          invocation of INITIALIZER is 41 and the remaining argument
                          (singular in this example) is 43 . Without C99 or similar support
                          for variable argument lists for macros, initializers that need to
                          contain commas are very problematic.



                          Correct header file3b.h included (instead of fileba.h) per
                          Denis Kniazhev




                          The next two files complete the source for prog4:



                          prog4.h



                          extern int increment(void);
                          extern int oddball_value(void);
                          extern void use_them(void);


                          prog4.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog4 uses prog4.c, file1b.c, file2b.c, prog4.h, file3b.h.


                          Header Guards



                          Any header should be protected against reinclusion, so that type
                          definitions (enum, struct or union types, or typedefs generally) do not
                          cause problems. The standard technique is to wrap the body of the
                          header in a header guard such as:



                          #ifndef FILE3B_H_INCLUDED
                          #define FILE3B_H_INCLUDED

                          ...contents of header...

                          #endif /* FILE3B_H_INCLUDED */


                          The header might be included twice indirectly. For example, if
                          file4b.h includes file3b.h for a type definition that isn't shown,
                          and file1b.c needs to use both header file4b.h and file3b.h, then
                          you have some more tricky issues to resolve. Clearly, you might revise
                          the header list to include just file4b.h. However, you might not be
                          aware of the internal dependencies — and the code should, ideally,
                          continue to work.



                          Further, it starts to get tricky because you might include file4b.h
                          before including file3b.h to generate the definitions, but the normal
                          header guards on file3b.h would prevent the header being reincluded.



                          So, you need to include the body of file3b.h at most once for
                          declarations, and at most once for definitions, but you might need both
                          in a single translation unit (TU — a combination of a source file and
                          the headers it uses).



                          Multiple inclusion with variable definitions



                          However, it can be done subject to a not too unreasonable constraint.
                          Let's introduce a new set of file names:




                          • external.h for the EXTERN macro definitions, etc.


                          • file1c.h to define types (notably, struct oddball, the type of oddball_struct).


                          • file2c.h to define or declare the global variables.


                          • file3c.c which defines the global variables.


                          • file4c.c which simply uses the global variables.


                          • file5c.c which shows that you can declare and then define the global variables.


                          • file6c.c which shows that you can define and then (attempt to) declare the global variables.

                          In these examples, file5c.c and file6c.c directly include the header
                          file2c.h several times, but that is the simplest way to show that the
                          mechanism works. It means that if the header was indirectly included
                          twice, it would also be safe.



                          The restrictions for this to work are:



                          1. The header defining or declaring the global variables may not itself
                            define any types.

                          2. Immediately before you include a header that should define variables,
                            you define the macro DEFINE_VARIABLES.

                          3. The header defining or declaring the variables has stylized contents.

                          external.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is invoked, it redefines the macros EXTERN, INITIALIZE
                          ** based on whether macro DEFINE_VARIABLES is currently defined.
                          */
                          #undef EXTERN
                          #undef INITIALIZE

                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZE(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZE(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */


                          file1c.h



                          #ifndef FILE1C_H_INCLUDED
                          #define FILE1C_H_INCLUDED

                          struct oddball

                          int a;
                          int b;
                          ;

                          extern void use_them(void);
                          extern int increment(void);
                          extern int oddball_value(void);

                          #endif /* FILE1C_H_INCLUDED */


                          file2c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2C_H_DEFINITIONS)
                          #undef FILE2C_H_INCLUDED
                          #endif

                          #ifndef FILE2C_H_INCLUDED
                          #define FILE2C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2C_H_INCLUDED */


                          file3c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file4c.c



                          #include "file2c.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          file5c.c



                          #include "file2c.h" /* Declare variables */

                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file6c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          #include "file2c.h" /* Declare variables */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next source file completes the source (provides a main program) for prog5, prog6 and prog7:



                          prog5.c



                          #include "file2c.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog5 uses prog5.c, file3c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog6 uses prog5.c, file5c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog7 uses prog5.c, file6c.c, file4c.c, file1c.h, file2c.h, external.h.


                          This scheme avoids most problems. You only run into a problem if a
                          header that defines variables (such as file2c.h) is included by
                          another header (say file7c.h) that defines variables. There isn't an
                          easy way around that other than "don't do it".



                          You can partially work around the problem by revising file2c.h into
                          file2d.h:



                          file2d.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2D_H_DEFINITIONS)
                          #undef FILE2D_H_INCLUDED
                          #endif

                          #ifndef FILE2D_H_INCLUDED
                          #define FILE2D_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2D_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2D_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2D_H_DEFINITIONS
                          #undef DEFINE_VARIABLES
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2D_H_INCLUDED */


                          The issue becomes 'should the header include #undef DEFINE_VARIABLES?'
                          If you omit that from the header and wrap any defining invocation with
                          #define and #undef:



                          #define DEFINE_VARIABLES
                          #include "file2c.h"
                          #undef DEFINE_VARIABLES


                          in the source code (so the headers never alter the value of
                          DEFINE_VARIABLES), then you should be clean. It is just a nuisance to
                          have to remember to write the the extra line. An alternative might be:



                          #define HEADER_DEFINING_VARIABLES "file2c.h"
                          #include "externdef.h"


                          externdef.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is included, the macro HEADER_DEFINING_VARIABLES should
                          ** be defined with the name (in quotes - or possibly angle brackets) of
                          ** the header to be included that defines variables when the macro
                          ** DEFINE_VARIABLES is defined. See also: external.h (which uses
                          ** DEFINE_VARIABLES and defines macros EXTERN and INITIALIZE
                          ** appropriately).
                          **
                          ** #define HEADER_DEFINING_VARIABLES "file2c.h"
                          ** #include "externdef.h"
                          */

                          #if defined(HEADER_DEFINING_VARIABLES)
                          #define DEFINE_VARIABLES
                          #include HEADER_DEFINING_VARIABLES
                          #undef DEFINE_VARIABLES
                          #undef HEADER_DEFINING_VARIABLES
                          #endif /* HEADER_DEFINING_VARIABLES */


                          This is getting a tad convoluted, but seems to be secure (using the
                          file2d.h, with no #undef DEFINE_VARIABLES in the file2d.h).



                          file7c.c



                          /* Declare variables */
                          #include "file2d.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Declare variables - again */
                          #include "file2d.h"

                          /* Define variables - again */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file8c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE8C_H_DEFINITIONS)
                          #undef FILE8C_H_INCLUDED
                          #endif

                          #ifndef FILE8C_H_INCLUDED
                          #define FILE8C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file2d.h" /* struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE8C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN struct oddball another INITIALIZE( 14, 34 );

                          #endif /* !DEFINE_VARIABLES || !FILE8C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE8C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE8C_H_INCLUDED */


                          file8c.c



                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file8c.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next two files complete the source for prog8 and prog9:



                          prog8.c



                          #include "file2d.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;



                          file9c.c



                          #include "file2d.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;




                          • prog8 uses prog8.c, file7c.c, file9c.c.


                          • prog9 uses prog8.c, file8c.c, file9c.c.


                          However, the problems are relatively unlikely to occur in practice,
                          especially if you take the standard advice to



                          Avoid global variables




                          Does this exposition miss anything?



                          Confession: The 'avoiding duplicated code' scheme outlined here was
                          developed because the issue affects some code I work on (but don't own),
                          and is a niggling concern with the scheme outlined in the first part of
                          the answer. However, the original scheme leaves you with just two
                          places to modify to keep variable definitions and declarations
                          synchronized, which is a big step forward over having exernal variable
                          declarations scattered throughout the code base (which really matters
                          when there are thousands of files in total). However, the code in the
                          files with the names fileNc.[ch] (plus external.h and externdef.h)
                          shows that it can be made to work. Clearly, it would not be hard to
                          create a header generator script to give you the standardized template
                          for a variable defining and declaring header file.



                          NB These are toy programs with just barely enough code to make them
                          marginally interesting. There is repetition within the examples that
                          could be removed, but isn't to simplify the pedagogical explanation.
                          (For example: the difference between prog5.c and prog8.c is the name
                          of one of the headers that are included. It would be possible to
                          reorganize the code so that the main() function was not repeated, but
                          it would conceal more than it revealed.)






                          share|improve this answer















                          Using extern is only of relevance when the program you're building
                          consists of multiple source files linked together, where some of the
                          variables defined, for example, in source file file1.c need to be
                          referenced in other source files, such as file2.c.



                          It is important to understand the difference between defining a
                          variable and declaring a
                          variable:



                          • A variable is declared when the compiler is informed that a
                            variable exists (and this is its type); it does not allocate the
                            storage for the variable at that point.

                          • A variable is defined when the compiler allocates the storage for
                            the variable.

                          You may declare a variable multiple times (though once is sufficient);
                          you may only define it once within a given scope.
                          A variable definition is also a declaration, but not all variable
                          declarations are definitions.



                          Best way to declare and define global variables



                          The clean, reliable way to declare and define global variables is to use
                          a header file to contain an extern declaration of the variable.



                          The header is included by the one source file that defines the variable
                          and by all the source files that reference the variable.
                          For each program, one source file (and only one source file) defines the
                          variable.
                          Similarly, one header file (and only one header file) should declare the
                          variable.
                          The header file is crucial; it enables cross-checking between
                          independent TUs (translation units — think source files) and ensures
                          consistency.



                          Although there are other ways of doing it, this method is simple and
                          reliable.
                          It is demonstrated by file3.h, file1.c and file2.c:



                          file3.h



                          extern int global_variable; /* Declaration of the variable */


                          file1.c



                          #include "file3.h" /* Declaration made available here */
                          #include "prog1.h" /* Function declarations */

                          /* Variable defined here */
                          int global_variable = 37; /* Definition checked against declaration */

                          int increment(void) return global_variable++;


                          file2.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);



                          That's the best way to declare and define global variables.




                          The next two files complete the source for prog1:



                          The complete programs shown use functions, so function declarations have
                          crept in.
                          Both C99 and C11 require functions to be declared or defined before they
                          are used (whereas C90 did not, for good reasons).
                          I use the keyword extern in front of function declarations in headers
                          for consistency — to match the extern in front of variable
                          declarations in headers.
                          Many people prefer not to use extern in front of function
                          declarations; the compiler doesn't care — and ultimately, neither do I
                          as long as you're consistent, at least within a source file.



                          prog1.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog1.c



                          #include "file3.h"
                          #include "prog1.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog1 uses prog1.c, file1.c, file2.c, file3.h and prog1.h.

                          The file prog1.mk is a makefile for prog1 only.
                          It will work with most versions of make produced since about the turn
                          of the millennium.
                          It is not tied specifically to GNU Make.



                          prog1.mk



                          # Minimal makefile for prog1

                          PROGRAM = prog1
                          FILES.c = prog1.c file1.c file2.c
                          FILES.h = prog1.h file3.h
                          FILES.o = $FILES.c:.c=.o

                          CC = gcc
                          SFLAGS = -std=c11
                          GFLAGS = -g
                          OFLAGS = -O3
                          WFLAG1 = -Wall
                          WFLAG2 = -Wextra
                          WFLAG3 = -Werror
                          WFLAG4 = -Wstrict-prototypes
                          WFLAG5 = -Wmissing-prototypes
                          WFLAGS = $WFLAG1 $WFLAG2 $WFLAG3 $WFLAG4 $WFLAG5
                          UFLAGS = # Set on command line only

                          CFLAGS = $SFLAGS $GFLAGS $OFLAGS $WFLAGS $UFLAGS
                          LDFLAGS =
                          LDLIBS =

                          all: $PROGRAM

                          $PROGRAM: $FILES.o
                          $CC -o $@ $CFLAGS $FILES.o $LDFLAGS $LDLIBS

                          prog1.o: $FILES.h
                          file1.o: $FILES.h
                          file2.o: $FILES.h

                          # If it exists, prog1.dSYM is a directory on macOS
                          DEBRIS = a.out core *~ *.dSYM
                          RM_FR = rm -fr

                          clean:
                          $RM_FR $FILES.o $PROGRAM $DEBRIS



                          Guidelines



                          Rules to be broken by experts only, and only with good reason:



                          • A header file only contains extern declarations of variables — never
                            static or unqualified variable definitions.

                          • For any given variable, only one header file declares it (SPOT —
                            Single Point of Truth).

                          • A source file never contains extern declarations of variables —
                            source files always include the (sole) header that declares them.

                          • For any given variable, exactly one source file defines the variable,
                            preferably initializing it too. (Although there is no need to
                            initialize explicitly to zero, it does no harm and can do some good,
                            because there can be only one initialized definition of a particular
                            global variable in a program).

                          • The source file that defines the variable also includes the header to
                            ensure that the definition and the declaration are consistent.

                          • A function should never need to declare a variable using extern.

                          • Avoid global variables whenever possible — use functions instead.

                          The source code and text of this answer are available in my
                          SOQ (Stack Overflow Questions)
                          repository on GitHub in the
                          src/so-0143-3204
                          sub-directory.



                          If you're not an experienced C programmer, you could (and perhaps
                          should) stop reading here.



                          Not so good way to define global variables



                          With some (indeed, many) C compilers, you can get away with what's
                          called a 'common' definition of a variable too.
                          'Common', here, refers to a technique used in Fortran for sharing
                          variables between source files, using a (possibly named) COMMON block.
                          What happens here is that each of a number of files provides a tentative
                          definition of the variable.
                          As long as no more than one file provides an initialized definition,
                          then the various files end up sharing a common single definition of the
                          variable:



                          file10.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void inc(void) i++;


                          file11.c



                          #include "prog2.h"

                          int i; /* Do not do this in portable code */

                          void dec(void) i--;


                          file12.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int i = 9; /* Do not do this in portable code */

                          void put(void) printf("i = %dn", i);


                          This technique does not conform to the letter of the C standard and the
                          'one definition rule' — it is officially undefined behaviour:




                          J.2 Undefined behavior



                          An identifier with external linkage is used, but in the program there
                          does not exist exactly one external definition for the identifier, or
                          the identifier is not used and there exist multiple external
                          definitions for the identifier (6.9).



                          §6.9 External definitions ¶5



                          An external definition is an external declaration that is also a
                          definition of a function (other than an inline definition) or an
                          object.
                          If an identifier declared with external linkage is used in an
                          expression (other than as part of the operand of a sizeof or
                          _Alignof operator whose result is an integer constant), somewhere in
                          the entire program there shall be exactly one external definition for
                          the identifier; otherwise, there shall be no more than
                          one.161)



                          161) Thus, if an identifier declared with external linkage
                          is not used in an expression, there need be no external definition for
                          it.




                          However, the C standard also lists it in informative Annex J as one of
                          the Common extensions.




                          J.5.11 Multiple external definitions



                          There may be more than one external definition for the identifier of
                          an object, with or without the explicit use of the keyword extern; if
                          the definitions disagree, or more than one is initialized, the
                          behavior is undefined (6.9.2).




                          Because this technique is not always supported, it is best to avoid
                          using it, especially if your code needs to be portable.
                          Using this technique, you can also end up with unintentional type
                          punning.
                          If one of the files declared i as a double instead of as an int,
                          C's type-unsafe linkers probably would not spot the mismatch.
                          If you're on a machine with 64-bit int and double, you'd not even
                          get a warning; on a machine with 32-bit int and 64-bit double, you'd
                          probably get a warning about the different sizes — the linker would
                          use the largest size, exactly as a Fortran program would take the
                          largest size of any common blocks.




                          The next two files complete the source for prog2:



                          prog2.h



                          extern void dec(void);
                          extern void put(void);
                          extern void inc(void);


                          prog2.c



                          #include "prog2.h"
                          #include <stdio.h>

                          int main(void)

                          inc();
                          put();
                          dec();
                          put();
                          dec();
                          put();




                          • prog2 uses prog2.c, file10.c, file11.c, file12.c, prog2.h.


                          Warning



                          As noted in comments here, and as stated in my answer to a similar
                          question, using multiple
                          definitions for a global variable leads to undefined behaviour (J.2;
                          §6.9), which is the standard's way of saying "anything could happen".
                          One of the things that can happen is that the program behaves as you
                          expect; and J.5.11 says, approximately, "you might be lucky more often
                          than you deserve".
                          But a program that relies on multiple definitions of an extern variable
                          — with or without the explicit 'extern' keyword — is not a strictly
                          conforming program and not guaranteed to work everywhere.
                          Equivalently: it contains a bug which may or may not show itself.



                          Violating the guidelines



                          There are, of course, many ways in which these guidelines can be broken.
                          Occasionally, there may be a good reason to break the guidelines, but
                          such occasions are extremely unusual.



                          faulty_header.h



                          int some_var; /* Do not do this in a header!!! */


                          Note 1: if the header defines the variable without the extern keyword,
                          then each file that includes the header creates a tentative definition
                          of the variable.
                          As noted previously, this will often work, but the C standard does not
                          guarantee that it will work.



                          broken_header.h



                          int some_var = 13; /* Only one source file in a program can use this */


                          Note 2: if the header defines and initializes the variable, then only
                          one source file in a given program can use the header.
                          Since headers are primarily for sharing information, it is a bit silly
                          to create one that can only be used once.



                          seldom_correct.h



                          static int hidden_global = 3; /* Each source file gets its own copy */


                          Note 3: if the header defines a static variable (with or without
                          initialization), then each source file ends up with its own private
                          version of the 'global' variable.



                          If the variable is actually a complex array, for example, this can lead
                          to extreme duplication of code. It can, very occasionally, be a
                          sensible way to achieve some effect, but that is very unusual.




                          Summary



                          Use the header technique I showed first.
                          It works reliably and everywhere.
                          Note, in particular, that the header declaring the global_variable is
                          included in every file that uses it — including the one that defines it.
                          This ensures that everything is self-consistent.



                          Similar concerns arise with declaring and defining functions —
                          analogous rules apply.
                          But the question was about variables specifically, so I've kept the
                          answer to variables only.



                          End of Original Answer



                          If you're not an experienced C programmer, you probably should stop reading here.




                          Late Major Addition



                          Avoiding Code Duplication



                          One concern that is sometimes (and legitimately) raised about the
                          'declarations in headers, definitions in source' mechanism described
                          here is that there are two files to be kept synchronized — the header
                          and the source. This is usually followed up with an observation that a
                          macro can be used so that the header serves double duty — normally
                          declaring the variables, but when a specific macro is set before the
                          header is included, it defines the variables instead.



                          Another concern can be that the variables need to be defined in each of
                          a number of 'main programs'. This is normally a spurious concern; you
                          can simply introduce a C source file to define the variables and link
                          the object file produced with each of the programs.



                          A typical scheme works like this, using the original global variable
                          illustrated in file3.h:



                          file3a.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #else
                          #define EXTERN extern
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable;


                          file1a.c



                          #define DEFINE_VARIABLES
                          #include "file3a.h" /* Variable defined - but not initialized */
                          #include "prog3.h"

                          int increment(void) return global_variable++;


                          file2a.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          void use_it(void)

                          printf("Global variable: %dn", global_variable++);




                          The next two files complete the source for prog3:



                          prog3.h



                          extern void use_it(void);
                          extern int increment(void);


                          prog3.c



                          #include "file3a.h"
                          #include "prog3.h"
                          #include <stdio.h>

                          int main(void)

                          use_it();
                          global_variable += 19;
                          use_it();
                          printf("Increment: %dn", increment());
                          return 0;




                          • prog3 uses prog3.c, file1a.c, file2a.c, file3a.h, prog3.h.


                          Variable initialization



                          The problem with this scheme as shown is that it does not provide for
                          initialization of the global variable. With C99 or C11 and variable argument
                          lists for macros, you could define a macro to support initialization too.
                          (With C89 and no support for variable argument lists in macros, there is no
                          easy way to handle arbitrarily long initializers.)



                          file3b.h



                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZER(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZER(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */

                          EXTERN int global_variable INITIALIZER(37);
                          EXTERN struct int a; int b; oddball_struct INITIALIZER( 41, 43 );


                          Reverse contents of #if and #else blocks, fixing bug identified by
                          Denis Kniazhev



                          file1b.c



                          #define DEFINE_VARIABLES
                          #include "file3b.h" /* Variables now defined and initialized */
                          #include "prog4.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file2b.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          Clearly, the code for the oddball structure is not what you'd normally
                          write, but it illustrates the point. The first argument to the second
                          invocation of INITIALIZER is 41 and the remaining argument
                          (singular in this example) is 43 . Without C99 or similar support
                          for variable argument lists for macros, initializers that need to
                          contain commas are very problematic.



                          Correct header file3b.h included (instead of fileba.h) per
                          Denis Kniazhev




                          The next two files complete the source for prog4:



                          prog4.h



                          extern int increment(void);
                          extern int oddball_value(void);
                          extern void use_them(void);


                          prog4.c



                          #include "file3b.h"
                          #include "prog4.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog4 uses prog4.c, file1b.c, file2b.c, prog4.h, file3b.h.


                          Header Guards



                          Any header should be protected against reinclusion, so that type
                          definitions (enum, struct or union types, or typedefs generally) do not
                          cause problems. The standard technique is to wrap the body of the
                          header in a header guard such as:



                          #ifndef FILE3B_H_INCLUDED
                          #define FILE3B_H_INCLUDED

                          ...contents of header...

                          #endif /* FILE3B_H_INCLUDED */


                          The header might be included twice indirectly. For example, if
                          file4b.h includes file3b.h for a type definition that isn't shown,
                          and file1b.c needs to use both header file4b.h and file3b.h, then
                          you have some more tricky issues to resolve. Clearly, you might revise
                          the header list to include just file4b.h. However, you might not be
                          aware of the internal dependencies — and the code should, ideally,
                          continue to work.



                          Further, it starts to get tricky because you might include file4b.h
                          before including file3b.h to generate the definitions, but the normal
                          header guards on file3b.h would prevent the header being reincluded.



                          So, you need to include the body of file3b.h at most once for
                          declarations, and at most once for definitions, but you might need both
                          in a single translation unit (TU — a combination of a source file and
                          the headers it uses).



                          Multiple inclusion with variable definitions



                          However, it can be done subject to a not too unreasonable constraint.
                          Let's introduce a new set of file names:




                          • external.h for the EXTERN macro definitions, etc.


                          • file1c.h to define types (notably, struct oddball, the type of oddball_struct).


                          • file2c.h to define or declare the global variables.


                          • file3c.c which defines the global variables.


                          • file4c.c which simply uses the global variables.


                          • file5c.c which shows that you can declare and then define the global variables.


                          • file6c.c which shows that you can define and then (attempt to) declare the global variables.

                          In these examples, file5c.c and file6c.c directly include the header
                          file2c.h several times, but that is the simplest way to show that the
                          mechanism works. It means that if the header was indirectly included
                          twice, it would also be safe.



                          The restrictions for this to work are:



                          1. The header defining or declaring the global variables may not itself
                            define any types.

                          2. Immediately before you include a header that should define variables,
                            you define the macro DEFINE_VARIABLES.

                          3. The header defining or declaring the variables has stylized contents.

                          external.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is invoked, it redefines the macros EXTERN, INITIALIZE
                          ** based on whether macro DEFINE_VARIABLES is currently defined.
                          */
                          #undef EXTERN
                          #undef INITIALIZE

                          #ifdef DEFINE_VARIABLES
                          #define EXTERN /* nothing */
                          #define INITIALIZE(...) = __VA_ARGS__
                          #else
                          #define EXTERN extern
                          #define INITIALIZE(...) /* nothing */
                          #endif /* DEFINE_VARIABLES */


                          file1c.h



                          #ifndef FILE1C_H_INCLUDED
                          #define FILE1C_H_INCLUDED

                          struct oddball

                          int a;
                          int b;
                          ;

                          extern void use_them(void);
                          extern int increment(void);
                          extern int oddball_value(void);

                          #endif /* FILE1C_H_INCLUDED */


                          file2c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2C_H_DEFINITIONS)
                          #undef FILE2C_H_INCLUDED
                          #endif

                          #ifndef FILE2C_H_INCLUDED
                          #define FILE2C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2C_H_INCLUDED */


                          file3c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file4c.c



                          #include "file2c.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;



                          file5c.c



                          #include "file2c.h" /* Declare variables */

                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file6c.c



                          #define DEFINE_VARIABLES
                          #include "file2c.h" /* Variables now defined and initialized */

                          #include "file2c.h" /* Declare variables */

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next source file completes the source (provides a main program) for prog5, prog6 and prog7:



                          prog5.c



                          #include "file2c.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;




                          • prog5 uses prog5.c, file3c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog6 uses prog5.c, file5c.c, file4c.c, file1c.h, file2c.h, external.h.


                          • prog7 uses prog5.c, file6c.c, file4c.c, file1c.h, file2c.h, external.h.


                          This scheme avoids most problems. You only run into a problem if a
                          header that defines variables (such as file2c.h) is included by
                          another header (say file7c.h) that defines variables. There isn't an
                          easy way around that other than "don't do it".



                          You can partially work around the problem by revising file2c.h into
                          file2d.h:



                          file2d.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE2D_H_DEFINITIONS)
                          #undef FILE2D_H_INCLUDED
                          #endif

                          #ifndef FILE2D_H_INCLUDED
                          #define FILE2D_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file1c.h" /* Type definition for struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE2D_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN int global_variable INITIALIZE(37);
                          EXTERN struct oddball oddball_struct INITIALIZE( 41, 43 );

                          #endif /* !DEFINE_VARIABLES || !FILE2D_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE2D_H_DEFINITIONS
                          #undef DEFINE_VARIABLES
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE2D_H_INCLUDED */


                          The issue becomes 'should the header include #undef DEFINE_VARIABLES?'
                          If you omit that from the header and wrap any defining invocation with
                          #define and #undef:



                          #define DEFINE_VARIABLES
                          #include "file2c.h"
                          #undef DEFINE_VARIABLES


                          in the source code (so the headers never alter the value of
                          DEFINE_VARIABLES), then you should be clean. It is just a nuisance to
                          have to remember to write the the extra line. An alternative might be:



                          #define HEADER_DEFINING_VARIABLES "file2c.h"
                          #include "externdef.h"


                          externdef.h



                          /*
                          ** This header must not contain header guards (like <assert.h> must not).
                          ** Each time it is included, the macro HEADER_DEFINING_VARIABLES should
                          ** be defined with the name (in quotes - or possibly angle brackets) of
                          ** the header to be included that defines variables when the macro
                          ** DEFINE_VARIABLES is defined. See also: external.h (which uses
                          ** DEFINE_VARIABLES and defines macros EXTERN and INITIALIZE
                          ** appropriately).
                          **
                          ** #define HEADER_DEFINING_VARIABLES "file2c.h"
                          ** #include "externdef.h"
                          */

                          #if defined(HEADER_DEFINING_VARIABLES)
                          #define DEFINE_VARIABLES
                          #include HEADER_DEFINING_VARIABLES
                          #undef DEFINE_VARIABLES
                          #undef HEADER_DEFINING_VARIABLES
                          #endif /* HEADER_DEFINING_VARIABLES */


                          This is getting a tad convoluted, but seems to be secure (using the
                          file2d.h, with no #undef DEFINE_VARIABLES in the file2d.h).



                          file7c.c



                          /* Declare variables */
                          #include "file2d.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Declare variables - again */
                          #include "file2d.h"

                          /* Define variables - again */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;


                          file8c.h



                          /* Standard prologue */
                          #if defined(DEFINE_VARIABLES) && !defined(FILE8C_H_DEFINITIONS)
                          #undef FILE8C_H_INCLUDED
                          #endif

                          #ifndef FILE8C_H_INCLUDED
                          #define FILE8C_H_INCLUDED

                          #include "external.h" /* Support macros EXTERN, INITIALIZE */
                          #include "file2d.h" /* struct oddball */

                          #if !defined(DEFINE_VARIABLES) || !defined(FILE8C_H_DEFINITIONS)

                          /* Global variable declarations / definitions */
                          EXTERN struct oddball another INITIALIZE( 14, 34 );

                          #endif /* !DEFINE_VARIABLES || !FILE8C_H_DEFINITIONS */

                          /* Standard epilogue */
                          #ifdef DEFINE_VARIABLES
                          #define FILE8C_H_DEFINITIONS
                          #endif /* DEFINE_VARIABLES */

                          #endif /* FILE8C_H_INCLUDED */


                          file8c.c



                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file2d.h"
                          #include "externdef.h"

                          /* Define variables */
                          #define HEADER_DEFINING_VARIABLES "file8c.h"
                          #include "externdef.h"

                          int increment(void) return global_variable++;
                          int oddball_value(void) return oddball_struct.a + oddball_struct.b;



                          The next two files complete the source for prog8 and prog9:



                          prog8.c



                          #include "file2d.h"
                          #include <stdio.h>

                          int main(void)

                          use_them();
                          global_variable += 19;
                          use_them();
                          printf("Increment: %dn", increment());
                          printf("Oddball: %dn", oddball_value());
                          return 0;



                          file9c.c



                          #include "file2d.h"
                          #include <stdio.h>

                          void use_them(void)

                          printf("Global variable: %dn", global_variable++);
                          oddball_struct.a += global_variable;
                          oddball_struct.b -= global_variable / 2;




                          • prog8 uses prog8.c, file7c.c, file9c.c.


                          • prog9 uses prog8.c, file8c.c, file9c.c.


                          However, the problems are relatively unlikely to occur in practice,
                          especially if you take the standard advice to



                          Avoid global variables




                          Does this exposition miss anything?



                          Confession: The 'avoiding duplicated code' scheme outlined here was
                          developed because the issue affects some code I work on (but don't own),
                          and is a niggling concern with the scheme outlined in the first part of
                          the answer. However, the original scheme leaves you with just two
                          places to modify to keep variable definitions and declarations
                          synchronized, which is a big step forward over having exernal variable
                          declarations scattered throughout the code base (which really matters
                          when there are thousands of files in total). However, the code in the
                          files with the names fileNc.[ch] (plus external.h and externdef.h)
                          shows that it can be made to work. Clearly, it would not be hard to
                          create a header generator script to give you the standardized template
                          for a variable defining and declaring header file.



                          NB These are toy programs with just barely enough code to make them
                          marginally interesting. There is repetition within the examples that
                          could be removed, but isn't to simplify the pedagogical explanation.
                          (For example: the difference between prog5.c and prog8.c is the name
                          of one of the headers that are included. It would be possible to
                          reorganize the code so that the main() function was not repeated, but
                          it would conceal more than it revealed.)







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Jul 3 '18 at 16:04

























                          answered Sep 16 '09 at 14:37









                          Jonathan LefflerJonathan Leffler

                          573k956881041




                          573k956881041







                          • 3





                            @litb: see Annex J.5.11 for the common definition - it is a common extension.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:19






                          • 3





                            @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:20






                          • 3





                            Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

                            – Johannes Schaub - litb
                            Sep 16 '09 at 15:30






                          • 3





                            @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

                            – Jonathan Leffler
                            Jan 16 '13 at 2:14






                          • 11





                            If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

                            – Jonathan Leffler
                            Aug 5 '14 at 3:28












                          • 3





                            @litb: see Annex J.5.11 for the common definition - it is a common extension.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:19






                          • 3





                            @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

                            – Jonathan Leffler
                            Sep 16 '09 at 15:20






                          • 3





                            Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

                            – Johannes Schaub - litb
                            Sep 16 '09 at 15:30






                          • 3





                            @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

                            – Jonathan Leffler
                            Jan 16 '13 at 2:14






                          • 11





                            If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

                            – Jonathan Leffler
                            Aug 5 '14 at 3:28







                          3




                          3





                          @litb: see Annex J.5.11 for the common definition - it is a common extension.

                          – Jonathan Leffler
                          Sep 16 '09 at 15:19





                          @litb: see Annex J.5.11 for the common definition - it is a common extension.

                          – Jonathan Leffler
                          Sep 16 '09 at 15:19




                          3




                          3





                          @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

                          – Jonathan Leffler
                          Sep 16 '09 at 15:20





                          @litb: and I agree it should be avoided - that's why it is in the section on 'Not so good way to define global variables'.

                          – Jonathan Leffler
                          Sep 16 '09 at 15:20




                          3




                          3





                          Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

                          – Johannes Schaub - litb
                          Sep 16 '09 at 15:30





                          Indeed it's a common extension, but it's undefined behavior for a program to rely on it. I just wasn't clear whether you were saying that this is allowed by C's own rules. Now i see you are saying it's just a common extension and to avoid it if you need your code to be portable. So i can upvote you without doubts. Really great answer IMHO :)

                          – Johannes Schaub - litb
                          Sep 16 '09 at 15:30




                          3




                          3





                          @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

                          – Jonathan Leffler
                          Jan 16 '13 at 2:14





                          @Zak: No. The conditional code in file3a.h is #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, removing comments and using slashes to mark the ends of lines. If DEFINE_VARIABLES is specified, then the variables should not have the extern prefix which would mark them as declarations instead of definitions. That, in turn, means that the compiler will allocate space for the variables, rather than simply recording their existence.

                          – Jonathan Leffler
                          Jan 16 '13 at 2:14




                          11




                          11





                          If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

                          – Jonathan Leffler
                          Aug 5 '14 at 3:28





                          If you stop at the top, it keeps simple things simple. As you read further down, it deals with more nuances, complications and details. I've just added two 'early stopping points' for less experienced C programmers — or C programmers who already know the subject. There's no need to read it all if you already know the answer (but let me know if you find a technical fault).

                          – Jonathan Leffler
                          Aug 5 '14 at 3:28













                          112














                          An extern variable is a declaration (thanks to sbi for the correction) of a variable which is defined in another translation unit. That means the storage for the variable is allocated in another file.



                          Say you have two .c-files test1.c and test2.c. If you define a global variable int test1_var; in test1.c and you'd like to access this variable in test2.c you have to use extern int test1_var; in test2.c.



                          Complete sample:



                          $ cat test1.c 
                          int test1_var = 5;
                          $ cat test2.c
                          #include <stdio.h>

                          extern int test1_var;

                          int main(void)
                          printf("test1_var = %dn", test1_var);
                          return 0;

                          $ gcc test1.c test2.c -o test
                          $ ./test
                          test1_var = 5





                          share|improve this answer




















                          • 18





                            There's no "pseudo-definitions". It's a declaration.

                            – sbi
                            Sep 16 '09 at 14:18






                          • 1





                            In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

                            – radiohead
                            Mar 24 '18 at 3:15







                          • 2





                            @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

                            – Jonathan Leffler
                            Jun 16 '18 at 19:44
















                          112














                          An extern variable is a declaration (thanks to sbi for the correction) of a variable which is defined in another translation unit. That means the storage for the variable is allocated in another file.



                          Say you have two .c-files test1.c and test2.c. If you define a global variable int test1_var; in test1.c and you'd like to access this variable in test2.c you have to use extern int test1_var; in test2.c.



                          Complete sample:



                          $ cat test1.c 
                          int test1_var = 5;
                          $ cat test2.c
                          #include <stdio.h>

                          extern int test1_var;

                          int main(void)
                          printf("test1_var = %dn", test1_var);
                          return 0;

                          $ gcc test1.c test2.c -o test
                          $ ./test
                          test1_var = 5





                          share|improve this answer




















                          • 18





                            There's no "pseudo-definitions". It's a declaration.

                            – sbi
                            Sep 16 '09 at 14:18






                          • 1





                            In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

                            – radiohead
                            Mar 24 '18 at 3:15







                          • 2





                            @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

                            – Jonathan Leffler
                            Jun 16 '18 at 19:44














                          112












                          112








                          112







                          An extern variable is a declaration (thanks to sbi for the correction) of a variable which is defined in another translation unit. That means the storage for the variable is allocated in another file.



                          Say you have two .c-files test1.c and test2.c. If you define a global variable int test1_var; in test1.c and you'd like to access this variable in test2.c you have to use extern int test1_var; in test2.c.



                          Complete sample:



                          $ cat test1.c 
                          int test1_var = 5;
                          $ cat test2.c
                          #include <stdio.h>

                          extern int test1_var;

                          int main(void)
                          printf("test1_var = %dn", test1_var);
                          return 0;

                          $ gcc test1.c test2.c -o test
                          $ ./test
                          test1_var = 5





                          share|improve this answer















                          An extern variable is a declaration (thanks to sbi for the correction) of a variable which is defined in another translation unit. That means the storage for the variable is allocated in another file.



                          Say you have two .c-files test1.c and test2.c. If you define a global variable int test1_var; in test1.c and you'd like to access this variable in test2.c you have to use extern int test1_var; in test2.c.



                          Complete sample:



                          $ cat test1.c 
                          int test1_var = 5;
                          $ cat test2.c
                          #include <stdio.h>

                          extern int test1_var;

                          int main(void)
                          printf("test1_var = %dn", test1_var);
                          return 0;

                          $ gcc test1.c test2.c -o test
                          $ ./test
                          test1_var = 5






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Feb 18 '17 at 20:49









                          jww

                          54.1k41234513




                          54.1k41234513










                          answered Sep 16 '09 at 14:12









                          Johannes WeissJohannes Weiss

                          39.7k1483120




                          39.7k1483120







                          • 18





                            There's no "pseudo-definitions". It's a declaration.

                            – sbi
                            Sep 16 '09 at 14:18






                          • 1





                            In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

                            – radiohead
                            Mar 24 '18 at 3:15







                          • 2





                            @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

                            – Jonathan Leffler
                            Jun 16 '18 at 19:44













                          • 18





                            There's no "pseudo-definitions". It's a declaration.

                            – sbi
                            Sep 16 '09 at 14:18






                          • 1





                            In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

                            – radiohead
                            Mar 24 '18 at 3:15







                          • 2





                            @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

                            – Jonathan Leffler
                            Jun 16 '18 at 19:44








                          18




                          18





                          There's no "pseudo-definitions". It's a declaration.

                          – sbi
                          Sep 16 '09 at 14:18





                          There's no "pseudo-definitions". It's a declaration.

                          – sbi
                          Sep 16 '09 at 14:18




                          1




                          1





                          In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

                          – radiohead
                          Mar 24 '18 at 3:15






                          In the above example, if I change the extern int test1_var; to int test1_var;, the linker (gcc 5.4.0) still passes. So, is extern really needed in this case?

                          – radiohead
                          Mar 24 '18 at 3:15





                          2




                          2





                          @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

                          – Jonathan Leffler
                          Jun 16 '18 at 19:44






                          @radiohead: In my answer, you will find the information that dropping the extern is a common extension that often works — and specifically works with GCC (but GCC is far from being the only compiler that supports it; it is prevalent on Unix systems). You can look for "J.5.11" or the section "Not so good way" in my answer (I know — it is long) and the text near that explains it (or tries to do so).

                          – Jonathan Leffler
                          Jun 16 '18 at 19:44












                          36














                          Extern is the keyword you use to declare that the variable itself resides in another translation unit.



                          So you can decide to use a variable in a translation unit and then access it from another one, then in the second one you declare it as extern and the symbol will be resolved by the linker.



                          If you don't declare it as extern you'll get 2 variables named the same but not related at all, and an error of multiple definitions of the variable.






                          share|improve this answer




















                          • 5





                            In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

                            – mjv
                            Sep 16 '09 at 14:19















                          36














                          Extern is the keyword you use to declare that the variable itself resides in another translation unit.



                          So you can decide to use a variable in a translation unit and then access it from another one, then in the second one you declare it as extern and the symbol will be resolved by the linker.



                          If you don't declare it as extern you'll get 2 variables named the same but not related at all, and an error of multiple definitions of the variable.






                          share|improve this answer




















                          • 5





                            In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

                            – mjv
                            Sep 16 '09 at 14:19













                          36












                          36








                          36







                          Extern is the keyword you use to declare that the variable itself resides in another translation unit.



                          So you can decide to use a variable in a translation unit and then access it from another one, then in the second one you declare it as extern and the symbol will be resolved by the linker.



                          If you don't declare it as extern you'll get 2 variables named the same but not related at all, and an error of multiple definitions of the variable.






                          share|improve this answer















                          Extern is the keyword you use to declare that the variable itself resides in another translation unit.



                          So you can decide to use a variable in a translation unit and then access it from another one, then in the second one you declare it as extern and the symbol will be resolved by the linker.



                          If you don't declare it as extern you'll get 2 variables named the same but not related at all, and an error of multiple definitions of the variable.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Sep 16 '09 at 14:21

























                          answered Sep 16 '09 at 14:11









                          Arkaitz JimenezArkaitz Jimenez

                          16.2k86395




                          16.2k86395







                          • 5





                            In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

                            – mjv
                            Sep 16 '09 at 14:19












                          • 5





                            In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

                            – mjv
                            Sep 16 '09 at 14:19







                          5




                          5





                          In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

                          – mjv
                          Sep 16 '09 at 14:19





                          In other words the translation unit where extern is used knows about this variable, its type etc. and hence allows the source code in the underlying logic to use it, but it does not allocate the variable, another translation unit will do that. If both translation units were to declare the variable normally, there would be effectily two physical locations for the variable, with the associated "wrong" references within the compiled code, and with the resulting ambiguity for the linker.

                          – mjv
                          Sep 16 '09 at 14:19











                          24














                          I like to think of an extern variable as a promise that you make to the compiler.



                          When encountering an extern, the compiler can only find out its type, not where it "lives", so it can't resolve the reference.



                          You are telling it, "Trust me. At link time this reference will be resolvable."






                          share|improve this answer























                          • More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

                            – Lie Ryan
                            Nov 30 '10 at 2:16















                          24














                          I like to think of an extern variable as a promise that you make to the compiler.



                          When encountering an extern, the compiler can only find out its type, not where it "lives", so it can't resolve the reference.



                          You are telling it, "Trust me. At link time this reference will be resolvable."






                          share|improve this answer























                          • More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

                            – Lie Ryan
                            Nov 30 '10 at 2:16













                          24












                          24








                          24







                          I like to think of an extern variable as a promise that you make to the compiler.



                          When encountering an extern, the compiler can only find out its type, not where it "lives", so it can't resolve the reference.



                          You are telling it, "Trust me. At link time this reference will be resolvable."






                          share|improve this answer













                          I like to think of an extern variable as a promise that you make to the compiler.



                          When encountering an extern, the compiler can only find out its type, not where it "lives", so it can't resolve the reference.



                          You are telling it, "Trust me. At link time this reference will be resolvable."







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Sep 16 '09 at 14:50









                          BuggieboyBuggieboy

                          2,84544375




                          2,84544375












                          • More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

                            – Lie Ryan
                            Nov 30 '10 at 2:16

















                          • More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

                            – Lie Ryan
                            Nov 30 '10 at 2:16
















                          More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

                          – Lie Ryan
                          Nov 30 '10 at 2:16





                          More generally, a declaration is a promise that the name will be resolvable to a exactly one definition at link time. An extern declares a variable without defining.

                          – Lie Ryan
                          Nov 30 '10 at 2:16











                          18














                          extern tells the compiler to trust you that the memory for this variable is declared elsewhere, so it doesnt try to allocate/check memory.



                          Therefore, you can compile a file that has reference to an extern, but you can not link if that memory is not declared somewhere.



                          Useful for global variables and libraries, but dangerous because the linker does not type check.






                          share|improve this answer























                          • The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

                            – sbi
                            Sep 16 '09 at 14:37















                          18














                          extern tells the compiler to trust you that the memory for this variable is declared elsewhere, so it doesnt try to allocate/check memory.



                          Therefore, you can compile a file that has reference to an extern, but you can not link if that memory is not declared somewhere.



                          Useful for global variables and libraries, but dangerous because the linker does not type check.






                          share|improve this answer























                          • The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

                            – sbi
                            Sep 16 '09 at 14:37













                          18












                          18








                          18







                          extern tells the compiler to trust you that the memory for this variable is declared elsewhere, so it doesnt try to allocate/check memory.



                          Therefore, you can compile a file that has reference to an extern, but you can not link if that memory is not declared somewhere.



                          Useful for global variables and libraries, but dangerous because the linker does not type check.






                          share|improve this answer













                          extern tells the compiler to trust you that the memory for this variable is declared elsewhere, so it doesnt try to allocate/check memory.



                          Therefore, you can compile a file that has reference to an extern, but you can not link if that memory is not declared somewhere.



                          Useful for global variables and libraries, but dangerous because the linker does not type check.







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Sep 16 '09 at 14:18









                          BenBBenB

                          5,99062530




                          5,99062530












                          • The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

                            – sbi
                            Sep 16 '09 at 14:37

















                          • The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

                            – sbi
                            Sep 16 '09 at 14:37
















                          The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

                          – sbi
                          Sep 16 '09 at 14:37





                          The memory isn't declared. See the answers to this question: stackoverflow.com/questions/1410563 for more details.

                          – sbi
                          Sep 16 '09 at 14:37











                          15














                          Adding an extern turns a variable definition into a variable declaration. See this thread as to what's the difference between a declaration and a definition.






                          share|improve this answer

























                          • What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

                            – user1150105
                            Nov 8 '12 at 19:07











                          • @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

                            – sbi
                            Nov 9 '12 at 9:12
















                          15














                          Adding an extern turns a variable definition into a variable declaration. See this thread as to what's the difference between a declaration and a definition.






                          share|improve this answer

























                          • What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

                            – user1150105
                            Nov 8 '12 at 19:07











                          • @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

                            – sbi
                            Nov 9 '12 at 9:12














                          15












                          15








                          15







                          Adding an extern turns a variable definition into a variable declaration. See this thread as to what's the difference between a declaration and a definition.






                          share|improve this answer















                          Adding an extern turns a variable definition into a variable declaration. See this thread as to what's the difference between a declaration and a definition.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited May 23 '17 at 12:18









                          Community

                          11




                          11










                          answered Sep 16 '09 at 14:16









                          sbisbi

                          167k40217400




                          167k40217400












                          • What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

                            – user1150105
                            Nov 8 '12 at 19:07











                          • @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

                            – sbi
                            Nov 9 '12 at 9:12


















                          • What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

                            – user1150105
                            Nov 8 '12 at 19:07











                          • @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

                            – sbi
                            Nov 9 '12 at 9:12

















                          What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

                          – user1150105
                          Nov 8 '12 at 19:07





                          What difference between int foo and extern int foo (file scope)? Both are declaration, isn't it?

                          – user1150105
                          Nov 8 '12 at 19:07













                          @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

                          – sbi
                          Nov 9 '12 at 9:12






                          @user14284: They are both declaration only in the sense that every definition is a declaration, too. But I linked to an explanation of this. ("See this thread as to what's the difference between a declaration and a definition.") Why don't you simple follow the link and read?

                          – sbi
                          Nov 9 '12 at 9:12












                          11














                          The correct interpretation of extern is that you tell something to the compiler. You tell the compiler that, despite not being present right now, the variable declared will somehow be found by the linker (typically in another object (file)). The linker will then be the lucky guy to find everything and put it together, whether you had some extern declarations or not.






                          share|improve this answer



























                            11














                            The correct interpretation of extern is that you tell something to the compiler. You tell the compiler that, despite not being present right now, the variable declared will somehow be found by the linker (typically in another object (file)). The linker will then be the lucky guy to find everything and put it together, whether you had some extern declarations or not.






                            share|improve this answer

























                              11












                              11








                              11







                              The correct interpretation of extern is that you tell something to the compiler. You tell the compiler that, despite not being present right now, the variable declared will somehow be found by the linker (typically in another object (file)). The linker will then be the lucky guy to find everything and put it together, whether you had some extern declarations or not.






                              share|improve this answer













                              The correct interpretation of extern is that you tell something to the compiler. You tell the compiler that, despite not being present right now, the variable declared will somehow be found by the linker (typically in another object (file)). The linker will then be the lucky guy to find everything and put it together, whether you had some extern declarations or not.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Jun 20 '12 at 23:43









                              Alex LockwoodAlex Lockwood

                              75.3k34184233




                              75.3k34184233





















                                  8














                                  In C a variable inside a file say example.c is given local scope. The compiler expects that the variable would have its definition inside the same file example.c and when it does not find the same , it would throw an error.A function on the other hand has by default global scope . Thus you do not have to explicitly mention to the compiler "look dude...you might find the definition of this function here". For a function including the file which contains its declaration is enough.(The file which you actually call a header file).
                                  For example consider the following 2 files :

                                  example.c



                                  #include<stdio.h>
                                  extern int a;
                                  main()
                                  printf("The value of a is <%d>n",a);



                                  example1.c



                                  int a = 5;


                                  Now when you compile the two files together, using the following commands :



                                  step 1)cc -o ex example.c example1.c
                                  step 2)./ex



                                  You get the following output : The value of a is <5>






                                  share|improve this answer





























                                    8














                                    In C a variable inside a file say example.c is given local scope. The compiler expects that the variable would have its definition inside the same file example.c and when it does not find the same , it would throw an error.A function on the other hand has by default global scope . Thus you do not have to explicitly mention to the compiler "look dude...you might find the definition of this function here". For a function including the file which contains its declaration is enough.(The file which you actually call a header file).
                                    For example consider the following 2 files :

                                    example.c



                                    #include<stdio.h>
                                    extern int a;
                                    main()
                                    printf("The value of a is <%d>n",a);



                                    example1.c



                                    int a = 5;


                                    Now when you compile the two files together, using the following commands :



                                    step 1)cc -o ex example.c example1.c
                                    step 2)./ex



                                    You get the following output : The value of a is <5>






                                    share|improve this answer



























                                      8












                                      8








                                      8







                                      In C a variable inside a file say example.c is given local scope. The compiler expects that the variable would have its definition inside the same file example.c and when it does not find the same , it would throw an error.A function on the other hand has by default global scope . Thus you do not have to explicitly mention to the compiler "look dude...you might find the definition of this function here". For a function including the file which contains its declaration is enough.(The file which you actually call a header file).
                                      For example consider the following 2 files :

                                      example.c



                                      #include<stdio.h>
                                      extern int a;
                                      main()
                                      printf("The value of a is <%d>n",a);



                                      example1.c



                                      int a = 5;


                                      Now when you compile the two files together, using the following commands :



                                      step 1)cc -o ex example.c example1.c
                                      step 2)./ex



                                      You get the following output : The value of a is <5>






                                      share|improve this answer















                                      In C a variable inside a file say example.c is given local scope. The compiler expects that the variable would have its definition inside the same file example.c and when it does not find the same , it would throw an error.A function on the other hand has by default global scope . Thus you do not have to explicitly mention to the compiler "look dude...you might find the definition of this function here". For a function including the file which contains its declaration is enough.(The file which you actually call a header file).
                                      For example consider the following 2 files :

                                      example.c



                                      #include<stdio.h>
                                      extern int a;
                                      main()
                                      printf("The value of a is <%d>n",a);



                                      example1.c



                                      int a = 5;


                                      Now when you compile the two files together, using the following commands :



                                      step 1)cc -o ex example.c example1.c
                                      step 2)./ex



                                      You get the following output : The value of a is <5>







                                      share|improve this answer














                                      share|improve this answer



                                      share|improve this answer








                                      edited Aug 20 '12 at 10:45









                                      jogabonito

                                      1,74952039




                                      1,74952039










                                      answered Jul 2 '12 at 9:11









                                      Phoenix225Phoenix225

                                      122511




                                      122511





















                                          7














                                          extern keyword is used with the variable for its identification as a global variable.




                                          It also represents that you can use the variable declared using extern
                                          keyword in any file though it is declared/defined in other file.







                                          share|improve this answer



























                                            7














                                            extern keyword is used with the variable for its identification as a global variable.




                                            It also represents that you can use the variable declared using extern
                                            keyword in any file though it is declared/defined in other file.







                                            share|improve this answer

























                                              7












                                              7








                                              7







                                              extern keyword is used with the variable for its identification as a global variable.




                                              It also represents that you can use the variable declared using extern
                                              keyword in any file though it is declared/defined in other file.







                                              share|improve this answer













                                              extern keyword is used with the variable for its identification as a global variable.




                                              It also represents that you can use the variable declared using extern
                                              keyword in any file though it is declared/defined in other file.








                                              share|improve this answer












                                              share|improve this answer



                                              share|improve this answer










                                              answered Aug 20 '12 at 10:19









                                              AnupAnup

                                              40955




                                              40955





















                                                  6














                                                  GCC ELF Linux implementation



                                                  main.c:



                                                  #include <stdio.h>

                                                  int not_extern_int = 1;
                                                  extern int extern_int;

                                                  void main()
                                                  printf("%dn", not_extern_int);
                                                  printf("%dn", extern_int);



                                                  Compile and decompile:



                                                  gcc -c main.c
                                                  readelf -s main.o


                                                  Output contains:



                                                  Num: Value Size Type Bind Vis Ndx Name
                                                  9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 not_extern_int
                                                  12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND extern_int


                                                  The System V ABI Update ELF spec "Symbol Table" chapter explains:




                                                  SHN_UNDEF This section table index means the symbol is undefined. When the link editor combines this object file with another that defines the indicated symbol, this file's references to the symbol will be linked to the actual definition.




                                                  which is basically the behavior the C standard gives to extern variables.



                                                  From now on, it is the job of the linker to make the final program, but the extern information has already been extracted from the source code into the object file.



                                                  Tested on GCC 4.8.



                                                  C++17 inline variables



                                                  In C++17, you might want to use inline variables instead of extern ones, as they are simple to use (can be defined just once on header) and more powerful (support constexpr). See: What does 'const static' mean in C and C++?






                                                  share|improve this answer




















                                                  • 3





                                                    It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                                                    – Jonathan Leffler
                                                    Aug 30 '15 at 14:57












                                                  • @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                                                    – Ciro Santilli 新疆改造中心 六四事件 法轮功
                                                    Sep 2 '15 at 14:52












                                                  • As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                                                    – Jonathan Leffler
                                                    Sep 2 '15 at 14:56
















                                                  6














                                                  GCC ELF Linux implementation



                                                  main.c:



                                                  #include <stdio.h>

                                                  int not_extern_int = 1;
                                                  extern int extern_int;

                                                  void main()
                                                  printf("%dn", not_extern_int);
                                                  printf("%dn", extern_int);



                                                  Compile and decompile:



                                                  gcc -c main.c
                                                  readelf -s main.o


                                                  Output contains:



                                                  Num: Value Size Type Bind Vis Ndx Name
                                                  9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 not_extern_int
                                                  12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND extern_int


                                                  The System V ABI Update ELF spec "Symbol Table" chapter explains:




                                                  SHN_UNDEF This section table index means the symbol is undefined. When the link editor combines this object file with another that defines the indicated symbol, this file's references to the symbol will be linked to the actual definition.




                                                  which is basically the behavior the C standard gives to extern variables.



                                                  From now on, it is the job of the linker to make the final program, but the extern information has already been extracted from the source code into the object file.



                                                  Tested on GCC 4.8.



                                                  C++17 inline variables



                                                  In C++17, you might want to use inline variables instead of extern ones, as they are simple to use (can be defined just once on header) and more powerful (support constexpr). See: What does 'const static' mean in C and C++?






                                                  share|improve this answer




















                                                  • 3





                                                    It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                                                    – Jonathan Leffler
                                                    Aug 30 '15 at 14:57












                                                  • @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                                                    – Ciro Santilli 新疆改造中心 六四事件 法轮功
                                                    Sep 2 '15 at 14:52












                                                  • As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                                                    – Jonathan Leffler
                                                    Sep 2 '15 at 14:56














                                                  6












                                                  6








                                                  6







                                                  GCC ELF Linux implementation



                                                  main.c:



                                                  #include <stdio.h>

                                                  int not_extern_int = 1;
                                                  extern int extern_int;

                                                  void main()
                                                  printf("%dn", not_extern_int);
                                                  printf("%dn", extern_int);



                                                  Compile and decompile:



                                                  gcc -c main.c
                                                  readelf -s main.o


                                                  Output contains:



                                                  Num: Value Size Type Bind Vis Ndx Name
                                                  9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 not_extern_int
                                                  12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND extern_int


                                                  The System V ABI Update ELF spec "Symbol Table" chapter explains:




                                                  SHN_UNDEF This section table index means the symbol is undefined. When the link editor combines this object file with another that defines the indicated symbol, this file's references to the symbol will be linked to the actual definition.




                                                  which is basically the behavior the C standard gives to extern variables.



                                                  From now on, it is the job of the linker to make the final program, but the extern information has already been extracted from the source code into the object file.



                                                  Tested on GCC 4.8.



                                                  C++17 inline variables



                                                  In C++17, you might want to use inline variables instead of extern ones, as they are simple to use (can be defined just once on header) and more powerful (support constexpr). See: What does 'const static' mean in C and C++?






                                                  share|improve this answer















                                                  GCC ELF Linux implementation



                                                  main.c:



                                                  #include <stdio.h>

                                                  int not_extern_int = 1;
                                                  extern int extern_int;

                                                  void main()
                                                  printf("%dn", not_extern_int);
                                                  printf("%dn", extern_int);



                                                  Compile and decompile:



                                                  gcc -c main.c
                                                  readelf -s main.o


                                                  Output contains:



                                                  Num: Value Size Type Bind Vis Ndx Name
                                                  9: 0000000000000000 4 OBJECT GLOBAL DEFAULT 3 not_extern_int
                                                  12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND extern_int


                                                  The System V ABI Update ELF spec "Symbol Table" chapter explains:




                                                  SHN_UNDEF This section table index means the symbol is undefined. When the link editor combines this object file with another that defines the indicated symbol, this file's references to the symbol will be linked to the actual definition.




                                                  which is basically the behavior the C standard gives to extern variables.



                                                  From now on, it is the job of the linker to make the final program, but the extern information has already been extracted from the source code into the object file.



                                                  Tested on GCC 4.8.



                                                  C++17 inline variables



                                                  In C++17, you might want to use inline variables instead of extern ones, as they are simple to use (can be defined just once on header) and more powerful (support constexpr). See: What does 'const static' mean in C and C++?







                                                  share|improve this answer














                                                  share|improve this answer



                                                  share|improve this answer








                                                  edited Feb 3 at 17:27

























                                                  answered May 29 '15 at 7:34









                                                  Ciro Santilli 新疆改造中心 六四事件 法轮功Ciro Santilli 新疆改造中心 六四事件 法轮功

                                                  148k34560475




                                                  148k34560475







                                                  • 3





                                                    It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                                                    – Jonathan Leffler
                                                    Aug 30 '15 at 14:57












                                                  • @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                                                    – Ciro Santilli 新疆改造中心 六四事件 法轮功
                                                    Sep 2 '15 at 14:52












                                                  • As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                                                    – Jonathan Leffler
                                                    Sep 2 '15 at 14:56













                                                  • 3





                                                    It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                                                    – Jonathan Leffler
                                                    Aug 30 '15 at 14:57












                                                  • @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                                                    – Ciro Santilli 新疆改造中心 六四事件 法轮功
                                                    Sep 2 '15 at 14:52












                                                  • As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                                                    – Jonathan Leffler
                                                    Sep 2 '15 at 14:56








                                                  3




                                                  3





                                                  It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                                                  – Jonathan Leffler
                                                  Aug 30 '15 at 14:57






                                                  It's not my down-vote, so I don't know. However, I'll proffer an opinion. Although looking at the output of readelf or nm can be helpful, you've not explained the fundamentals of how to make use of extern, nor completed the first program with the actual definition. Your code doesn't even use notExtern. There's a nomenclature problem, too: although notExtern is defined here rather than declared with extern, it is an external variable that could be accessed by other source files if those translation units contained a suitable declaration (which would need extern int notExtern;!).

                                                  – Jonathan Leffler
                                                  Aug 30 '15 at 14:57














                                                  @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                                                  – Ciro Santilli 新疆改造中心 六四事件 法轮功
                                                  Sep 2 '15 at 14:52






                                                  @JonathanLeffler thanks for the feedback! The standard behavior and usage recommendations have already been done in other answers, so I decided to show the implementation a bit as that really helped me grasp what is going on. Not using notExtern was ugly, fixed it. About nomenclature, let me know if you have a better name. Of course that would not be a good name for an actual program, but I think it fits the didactic role well here.

                                                  – Ciro Santilli 新疆改造中心 六四事件 法轮功
                                                  Sep 2 '15 at 14:52














                                                  As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                                                  – Jonathan Leffler
                                                  Sep 2 '15 at 14:56






                                                  As to names, what about global_def for the variable defined here, and extern_ref for the variable defined in some other module? Would they have suitably clear symmetry? You still end up with int extern_ref = 57; or something like that in the file where it is defined, so the name isn't quite ideal, but within the context of the single source file, it is a reasonable choice. Having extern int global_def; in a header isn't as much of a problem, it seems to me. Entirely up to you, of course.

                                                  – Jonathan Leffler
                                                  Sep 2 '15 at 14:56












                                                  5














                                                  extern
                                                  allows one module of your program to access a global variable or function declared in another module of your program.
                                                  You usually have extern variables declared in header files.



                                                  If you don't want a program to access your variables or functions, you use static which tells the compiler that this variable or function cannot be used outside of this module.






                                                  share|improve this answer





























                                                    5














                                                    extern
                                                    allows one module of your program to access a global variable or function declared in another module of your program.
                                                    You usually have extern variables declared in header files.



                                                    If you don't want a program to access your variables or functions, you use static which tells the compiler that this variable or function cannot be used outside of this module.






                                                    share|improve this answer



























                                                      5












                                                      5








                                                      5







                                                      extern
                                                      allows one module of your program to access a global variable or function declared in another module of your program.
                                                      You usually have extern variables declared in header files.



                                                      If you don't want a program to access your variables or functions, you use static which tells the compiler that this variable or function cannot be used outside of this module.






                                                      share|improve this answer















                                                      extern
                                                      allows one module of your program to access a global variable or function declared in another module of your program.
                                                      You usually have extern variables declared in header files.



                                                      If you don't want a program to access your variables or functions, you use static which tells the compiler that this variable or function cannot be used outside of this module.







                                                      share|improve this answer














                                                      share|improve this answer



                                                      share|improve this answer








                                                      edited Sep 2 '15 at 15:00









                                                      Jonathan Leffler

                                                      573k956881041




                                                      573k956881041










                                                      answered Oct 3 '12 at 4:58









                                                      loganaayaheeloganaayahee

                                                      6321613




                                                      6321613





















                                                          5














                                                          extern simply means a variable is defined elsewhere (e.g., in another file).






                                                          share|improve this answer





























                                                            5














                                                            extern simply means a variable is defined elsewhere (e.g., in another file).






                                                            share|improve this answer



























                                                              5












                                                              5








                                                              5







                                                              extern simply means a variable is defined elsewhere (e.g., in another file).






                                                              share|improve this answer















                                                              extern simply means a variable is defined elsewhere (e.g., in another file).







                                                              share|improve this answer














                                                              share|improve this answer



                                                              share|improve this answer








                                                              edited May 5 '18 at 6:34









                                                              Jonathan Leffler

                                                              573k956881041




                                                              573k956881041










                                                              answered Jan 27 '16 at 19:47









                                                              GeremiaGeremia

                                                              1,3331725




                                                              1,3331725





















                                                                  4














                                                                  First off, the extern keyword is not used for defining a variable; rather it is used for declaring a variable. I can say extern is a storage class, not a data type.



                                                                  extern is used to let other C files or external components know this variable is already defined somewhere. Example: if you are building a library, no need to define global variable mandatorily somewhere in library itself. The library will be compiled directly, but while linking the file, it checks for the definition.






                                                                  share|improve this answer





























                                                                    4














                                                                    First off, the extern keyword is not used for defining a variable; rather it is used for declaring a variable. I can say extern is a storage class, not a data type.



                                                                    extern is used to let other C files or external components know this variable is already defined somewhere. Example: if you are building a library, no need to define global variable mandatorily somewhere in library itself. The library will be compiled directly, but while linking the file, it checks for the definition.






                                                                    share|improve this answer



























                                                                      4












                                                                      4








                                                                      4







                                                                      First off, the extern keyword is not used for defining a variable; rather it is used for declaring a variable. I can say extern is a storage class, not a data type.



                                                                      extern is used to let other C files or external components know this variable is already defined somewhere. Example: if you are building a library, no need to define global variable mandatorily somewhere in library itself. The library will be compiled directly, but while linking the file, it checks for the definition.






                                                                      share|improve this answer















                                                                      First off, the extern keyword is not used for defining a variable; rather it is used for declaring a variable. I can say extern is a storage class, not a data type.



                                                                      extern is used to let other C files or external components know this variable is already defined somewhere. Example: if you are building a library, no need to define global variable mandatorily somewhere in library itself. The library will be compiled directly, but while linking the file, it checks for the definition.







                                                                      share|improve this answer














                                                                      share|improve this answer



                                                                      share|improve this answer








                                                                      edited Sep 2 '15 at 15:04









                                                                      Jonathan Leffler

                                                                      573k956881041




                                                                      573k956881041










                                                                      answered Aug 9 '12 at 9:21









                                                                      user1270846user1270846

                                                                      1066




                                                                      1066





















                                                                          4














                                                                           declare | define | initialize |
                                                                          ----------------------------------

                                                                          extern int a; yes no no
                                                                          -------------
                                                                          int a = 2019; yes yes yes
                                                                          -------------
                                                                          int a; yes yes no
                                                                          -------------


                                                                          Declaration won't allocate memory (the variable must be defined for memory allocation) but the definition will.
                                                                          This is just another simple view on the extern keyword since the other answers are really great.






                                                                          share|improve this answer





























                                                                            4














                                                                             declare | define | initialize |
                                                                            ----------------------------------

                                                                            extern int a; yes no no
                                                                            -------------
                                                                            int a = 2019; yes yes yes
                                                                            -------------
                                                                            int a; yes yes no
                                                                            -------------


                                                                            Declaration won't allocate memory (the variable must be defined for memory allocation) but the definition will.
                                                                            This is just another simple view on the extern keyword since the other answers are really great.






                                                                            share|improve this answer



























                                                                              4












                                                                              4








                                                                              4







                                                                               declare | define | initialize |
                                                                              ----------------------------------

                                                                              extern int a; yes no no
                                                                              -------------
                                                                              int a = 2019; yes yes yes
                                                                              -------------
                                                                              int a; yes yes no
                                                                              -------------


                                                                              Declaration won't allocate memory (the variable must be defined for memory allocation) but the definition will.
                                                                              This is just another simple view on the extern keyword since the other answers are really great.






                                                                              share|improve this answer















                                                                               declare | define | initialize |
                                                                              ----------------------------------

                                                                              extern int a; yes no no
                                                                              -------------
                                                                              int a = 2019; yes yes yes
                                                                              -------------
                                                                              int a; yes yes no
                                                                              -------------


                                                                              Declaration won't allocate memory (the variable must be defined for memory allocation) but the definition will.
                                                                              This is just another simple view on the extern keyword since the other answers are really great.







                                                                              share|improve this answer














                                                                              share|improve this answer



                                                                              share|improve this answer








                                                                              edited Jan 9 at 20:56

























                                                                              answered Jan 9 at 20:50









                                                                              Lucian NutLucian Nut

                                                                              139213




                                                                              139213





















                                                                                  3














                                                                                  extern is used so one first.c file can have full access to a global parameter in another second.c file.



                                                                                  The extern can be declared in the first.c file or in any of the header files first.c includes.






                                                                                  share|improve this answer




















                                                                                  • 3





                                                                                    Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                                                                                    – Jonathan Leffler
                                                                                    Sep 2 '15 at 15:09















                                                                                  3














                                                                                  extern is used so one first.c file can have full access to a global parameter in another second.c file.



                                                                                  The extern can be declared in the first.c file or in any of the header files first.c includes.






                                                                                  share|improve this answer




















                                                                                  • 3





                                                                                    Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                                                                                    – Jonathan Leffler
                                                                                    Sep 2 '15 at 15:09













                                                                                  3












                                                                                  3








                                                                                  3







                                                                                  extern is used so one first.c file can have full access to a global parameter in another second.c file.



                                                                                  The extern can be declared in the first.c file or in any of the header files first.c includes.






                                                                                  share|improve this answer















                                                                                  extern is used so one first.c file can have full access to a global parameter in another second.c file.



                                                                                  The extern can be declared in the first.c file or in any of the header files first.c includes.







                                                                                  share|improve this answer














                                                                                  share|improve this answer



                                                                                  share|improve this answer








                                                                                  edited Sep 2 '15 at 15:06









                                                                                  Jonathan Leffler

                                                                                  573k956881041




                                                                                  573k956881041










                                                                                  answered Sep 1 '14 at 7:35









                                                                                  shohamshoham

                                                                                  25319




                                                                                  25319







                                                                                  • 3





                                                                                    Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                                                                                    – Jonathan Leffler
                                                                                    Sep 2 '15 at 15:09












                                                                                  • 3





                                                                                    Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                                                                                    – Jonathan Leffler
                                                                                    Sep 2 '15 at 15:09







                                                                                  3




                                                                                  3





                                                                                  Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                                                                                  – Jonathan Leffler
                                                                                  Sep 2 '15 at 15:09





                                                                                  Note that the extern declaration should be in a header, not in first.c, so that if the type changes, the declaration will change too. Also, the header that declares the variable should be included by second.c to ensure that the definition is consistent with the declaration. The declaration in the header is the glue that holds it all together; it allows the files to be compiled separately but ensures they have a consistent view of the type of the global variable.

                                                                                  – Jonathan Leffler
                                                                                  Sep 2 '15 at 15:09











                                                                                  1














                                                                                  With xc8 you have to be careful about declaring a variable
                                                                                  as the same type in each file as you could , erroneously,
                                                                                  declare something an int in one file and a char say in another.
                                                                                  This could lead to corruption of variables.



                                                                                  This problem was elegantly solved in a microchip forum some 15 years ago
                                                                                  /* See "http:www.htsoft.com" /
                                                                                  /
                                                                                  "forum/all/showflat.php/Cat/0/Number/18766/an/0/page/0#18766"



                                                                                  But this link seems to no longer work...



                                                                                  So I;ll quickly try to explain it;
                                                                                  make a file called global.h.



                                                                                  In it declare the following



                                                                                  #ifdef MAIN_C
                                                                                  #define GLOBAL
                                                                                  /* #warning COMPILING MAIN.C */
                                                                                  #else
                                                                                  #define GLOBAL extern
                                                                                  #endif
                                                                                  GLOBAL unsigned char testing_mode; // example var used in several C files


                                                                                  Now in the file main.c



                                                                                  #define MAIN_C 1
                                                                                  #include "global.h"
                                                                                  #undef MAIN_C


                                                                                  This means in main.c the variable will be declared as an unsigned char.



                                                                                  Now in other files simply including global.h will
                                                                                  have it declared as an extern for that file.



                                                                                  extern unsigned char testing_mode;


                                                                                  But it will be correctly declared as an unsigned char.



                                                                                  The old forum post probably explained this a bit more clearly.
                                                                                  But this is a real potential gotcha when using a compiler
                                                                                  that allows you to declare a variable in one file and then declare it extern as a different type in another. The problems associated with
                                                                                  that are if you say declared testing_mode as an int in another file
                                                                                  it would think it was a 16 bit var and overwrite some other part of ram, potentially corrupting another variable. Difficult to debug!






                                                                                  share|improve this answer





























                                                                                    1














                                                                                    With xc8 you have to be careful about declaring a variable
                                                                                    as the same type in each file as you could , erroneously,
                                                                                    declare something an int in one file and a char say in another.
                                                                                    This could lead to corruption of variables.



                                                                                    This problem was elegantly solved in a microchip forum some 15 years ago
                                                                                    /* See "http:www.htsoft.com" /
                                                                                    /
                                                                                    "forum/all/showflat.php/Cat/0/Number/18766/an/0/page/0#18766"



                                                                                    But this link seems to no longer work...



                                                                                    So I;ll quickly try to explain it;
                                                                                    make a file called global.h.



                                                                                    In it declare the following



                                                                                    #ifdef MAIN_C
                                                                                    #define GLOBAL
                                                                                    /* #warning COMPILING MAIN.C */
                                                                                    #else
                                                                                    #define GLOBAL extern
                                                                                    #endif
                                                                                    GLOBAL unsigned char testing_mode; // example var used in several C files


                                                                                    Now in the file main.c



                                                                                    #define MAIN_C 1
                                                                                    #include "global.h"
                                                                                    #undef MAIN_C


                                                                                    This means in main.c the variable will be declared as an unsigned char.



                                                                                    Now in other files simply including global.h will
                                                                                    have it declared as an extern for that file.



                                                                                    extern unsigned char testing_mode;


                                                                                    But it will be correctly declared as an unsigned char.



                                                                                    The old forum post probably explained this a bit more clearly.
                                                                                    But this is a real potential gotcha when using a compiler
                                                                                    that allows you to declare a variable in one file and then declare it extern as a different type in another. The problems associated with
                                                                                    that are if you say declared testing_mode as an int in another file
                                                                                    it would think it was a 16 bit var and overwrite some other part of ram, potentially corrupting another variable. Difficult to debug!






                                                                                    share|improve this answer



























                                                                                      1












                                                                                      1








                                                                                      1







                                                                                      With xc8 you have to be careful about declaring a variable
                                                                                      as the same type in each file as you could , erroneously,
                                                                                      declare something an int in one file and a char say in another.
                                                                                      This could lead to corruption of variables.



                                                                                      This problem was elegantly solved in a microchip forum some 15 years ago
                                                                                      /* See "http:www.htsoft.com" /
                                                                                      /
                                                                                      "forum/all/showflat.php/Cat/0/Number/18766/an/0/page/0#18766"



                                                                                      But this link seems to no longer work...



                                                                                      So I;ll quickly try to explain it;
                                                                                      make a file called global.h.



                                                                                      In it declare the following



                                                                                      #ifdef MAIN_C
                                                                                      #define GLOBAL
                                                                                      /* #warning COMPILING MAIN.C */
                                                                                      #else
                                                                                      #define GLOBAL extern
                                                                                      #endif
                                                                                      GLOBAL unsigned char testing_mode; // example var used in several C files


                                                                                      Now in the file main.c



                                                                                      #define MAIN_C 1
                                                                                      #include "global.h"
                                                                                      #undef MAIN_C


                                                                                      This means in main.c the variable will be declared as an unsigned char.



                                                                                      Now in other files simply including global.h will
                                                                                      have it declared as an extern for that file.



                                                                                      extern unsigned char testing_mode;


                                                                                      But it will be correctly declared as an unsigned char.



                                                                                      The old forum post probably explained this a bit more clearly.
                                                                                      But this is a real potential gotcha when using a compiler
                                                                                      that allows you to declare a variable in one file and then declare it extern as a different type in another. The problems associated with
                                                                                      that are if you say declared testing_mode as an int in another file
                                                                                      it would think it was a 16 bit var and overwrite some other part of ram, potentially corrupting another variable. Difficult to debug!






                                                                                      share|improve this answer















                                                                                      With xc8 you have to be careful about declaring a variable
                                                                                      as the same type in each file as you could , erroneously,
                                                                                      declare something an int in one file and a char say in another.
                                                                                      This could lead to corruption of variables.



                                                                                      This problem was elegantly solved in a microchip forum some 15 years ago
                                                                                      /* See "http:www.htsoft.com" /
                                                                                      /
                                                                                      "forum/all/showflat.php/Cat/0/Number/18766/an/0/page/0#18766"



                                                                                      But this link seems to no longer work...



                                                                                      So I;ll quickly try to explain it;
                                                                                      make a file called global.h.



                                                                                      In it declare the following



                                                                                      #ifdef MAIN_C
                                                                                      #define GLOBAL
                                                                                      /* #warning COMPILING MAIN.C */
                                                                                      #else
                                                                                      #define GLOBAL extern
                                                                                      #endif
                                                                                      GLOBAL unsigned char testing_mode; // example var used in several C files


                                                                                      Now in the file main.c



                                                                                      #define MAIN_C 1
                                                                                      #include "global.h"
                                                                                      #undef MAIN_C


                                                                                      This means in main.c the variable will be declared as an unsigned char.



                                                                                      Now in other files simply including global.h will
                                                                                      have it declared as an extern for that file.



                                                                                      extern unsigned char testing_mode;


                                                                                      But it will be correctly declared as an unsigned char.



                                                                                      The old forum post probably explained this a bit more clearly.
                                                                                      But this is a real potential gotcha when using a compiler
                                                                                      that allows you to declare a variable in one file and then declare it extern as a different type in another. The problems associated with
                                                                                      that are if you say declared testing_mode as an int in another file
                                                                                      it would think it was a 16 bit var and overwrite some other part of ram, potentially corrupting another variable. Difficult to debug!







                                                                                      share|improve this answer














                                                                                      share|improve this answer



                                                                                      share|improve this answer








                                                                                      edited Oct 9 '18 at 12:16

























                                                                                      answered Oct 9 '18 at 10:01









                                                                                      user50619user50619

                                                                                      200212




                                                                                      200212















                                                                                          protected by Lundin Aug 26 '15 at 14:18



                                                                                          Thank you for your interest in this question.
                                                                                          Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                                                                                          Would you like to answer one of these unanswered questions instead?



                                                                                          Popular posts from this blog

                                                                                          How to get text form Clipboard with JavaScript in Firefox 56?How to validate an email address in JavaScript?How do JavaScript closures work?How do I remove a property from a JavaScript object?How do you get a timestamp in JavaScript?How do I copy to the clipboard in JavaScript?How do I include a JavaScript file in another JavaScript file?Get the current URL with JavaScript?How to replace all occurrences of a string in JavaScriptHow to check whether a string contains a substring in JavaScript?How do I remove a particular element from an array in JavaScript?

                                                                                          Can't initialize raids on a new ASUS Prime B360M-A motherboard2019 Community Moderator ElectionSimilar to RAID config yet more like mirroring solution?Can't get motherboard serial numberWhy does the BIOS entry point start with a WBINVD instruction?UEFI performance Asus Maximus V Extreme

                                                                                          List of MPs elected to the English parliament in 1640 (April) Contents List of constituencies and members See also Notes References Navigation menueNational Archives – The Glynde Place ArchivesCobbett's Parliamentary history of England, from the Norman Conquest in 1066 to the year 1803'Aldermen in Parliament', The Aldermen of the City of London: Temp. Henry III – 1912onepage&q&f&#61, false 229