Do variables declared in a header file give separate copies of the variables to each .c file that includes the header?

Let’s start with a case that is fully defined by the C standard. If file.h contains extern int x;, it declares an identifier x to refer to some int object. This declaration is a part of each of file_1.c and file_2.c during compilation, and it is “made to refer to the same object” by linkage, per C 2018 6.2.2.

In this case, extern int x; is merely a declaration that does not define x. Some other declaration must define x. This could be done by putting int x; or int x = value; in file_1.c or file_2.c. Then the answer to your question would be that extern int x; in multiple source files would refer to the same object.

In the case you ask about, with int x; in file.h, the behavior is not fully defined by the C standard. Per C 2018 6.9.2, this is a tentative definition. If there is no regular definition of x, the C standard says the tentative definition results in x being defined as if it were initialized to zero. (In contrast, a declaration with an initializers, such as int x = 0;, is a regular definition, not a tentative definition.)

In that case, both file_1.c and file_2.c define x. So each file has its own definition. Then the C standard does not define the behavior, per 6.9 5, which says there shall be no more than one definition for such an identifier (and exactly one if it is actually used in an expression).

Since the C standard does not define the behavior, C implementations may. Until recently, GCC, Clang, and Unix tools treated tentative definitions differently from regular definitions. Multiple tentative definitions were allowed, and they were coalesced to form one definition. So, the answer to your question in this case is mixed: when int x; appears in multiple source files, it nominally refers to “different” objects in some interpretation of the C standard during compilation, but linking resolves it to the same object.

Recent versions of GCC changed this behavior. By default, tentative definitions are treated more like regular definitions, so multiple tentative definitions will result in a link error. In this case, the answer to your question is that when int x; appears in multiple source files, it refers to different objects, and this prevents the program from linking.

(This change in GCC started in version 10. The old behavior can be requested with the command-line switch -fcommon or by applying the attribute __attribute__((__common__)) to an identifier.)

Leave a Comment