The problem of defining global variables in the C language header file

Source: Internet
Author: User

The problem is that this begins:

Recently looking at a php extension source, compile the time encountered a problem:

Ld:1 duplicate symbol for architecture x86_64

Take a closer look at the source code, found in the header file in the definition of global variables.

After simplifying it, you can understand this:

T1.h#ifndef t1_h#define T1_hint a = 0; #endif//------------------//t1.c#include "T1.h"#include "t2.h" int Main () {    return 0;} -----------------//t2.h#include "T1.h"//empty//----------------//t2.c#include "t2.h"//empty//-------  

Can the two C files be compiled? Presumably a bit of experience will say no, redefined.

So is this really the case? Not so simple.

    • The first question, does the #ifndef macro prevent redefinition (redefinition)?

Answer: Yes. However, it is in a single translation unit (wiki translation Unit).

#ifndef header file macros are called include Guards (wiki)

We know that a complete compilation process is

ONE.C--- preprocessor , tmp.c ( temporary), COMPILER, One.obj, LINKE R -One.exe

These three processes, and during the precompilation phase, the include file is expanded, and we use the CC-E command to view the results of the t1.c precompilation:

?  T  cc-E t1.c      # 1 "t1.c"# 1 "<built-in>" 1# 1 "<built-in>" 3# 321 "<built-in>" 3<  c10># 1 "<command line>" 1# 1 "<built-in>" 2# 1 "t1.c" 2# 1 "./t1.h" 1int a = 0; # 3 "t1.c" 2# 1 "./t2.h" 1# 4 "t1.c" 2int Main (void) {return 0;}       

Seeing the compiler unfold the t1.h, we see the definition of a.

In the pre-compilation results of t2.c, we also see the expansion definition of a:

?  T  cc-E t2.c  # 1 "t2.c"# 1 "<built-in>" 1# 1 "<built-in>" 3# 321 "<built-in>" 3< c7># 1 "<command line>" 1# 1 "<built-in>" 2# 1 "t2.c" 2# 1 "./t2.h" 1# 1 "./t1.h" 1int A = 0 ; # 2 "./t2.h" 2# 2 "t2.c" 2          

So at the link stage, the compiler will see the definition of two A. The reason is that the include guards only works within the same translation unit (the compilation process of a C file and an include file), and two compilation units are compiled separately, so you can't perceive another #ifdefine content, You can understand this:

t1.c, T1.s, t2.o                                                       *->- t.otu                           /t2.c   , T2.s-T2.O

Therefore, in the header file is not supposed to define the variable, should only declare.

Include guards is a circular reference issue that prevents two of files from referencing each other. Readers can try to remove the include guards to see the effect.

The answers above also explain why the include guards does not play a role in preventing redefinition in this example.

So, how do you force a global variable to be defined in a header file?

The correct approach is the header file Declare,c file define, the commonplace problem, no longer repeat. Here are two tips: for a function, someone gives you a way to add inline or static keywords.

Or someone who's just doing it:

#ifdef define_globals#define extern#else#define extern extern#endifextern int global1; EXTERN int global2; 

So is it really wrong to define global variables in the header file?

The answer is not necessarily.

If we write such a C file:

int a;int a;int main (void) {    return 0;}   

You must think it's a redefinition, but you can try CC, and you won't get an error or even warning.

The reason for this is that the definition in tentative defination,c99 is

A declaration of a identifier for an object the have file scope without an initializer, and without a storage-class speci Fier or with the storage-class specifier static, constitutes a tentative definition. If A translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no E Xternal definition for this identifier, then the behavior is exactly as if the translation unit contains a file scope decl Aration of that identifier, with the composite type as of the the the Translation Unit, with an initializer equal to 0.

The implication is that if a variable is declare, but not initialized, and after the same translation unit has not been initialized, the variable should be assigned a value of 0. So, if you write in the header file according to the rules of C99

T1.h int A;

Will still be compiled to int a = 0. So multiple inclusions will still redefine the error.

and GCC VC does not fully follow this standard, C99 in the back of a paragraph:

multiple external definitions

There than one external definition for the identifier of a object, with or without the explicit use of the KE Yword extern; If the definitions disagree, or more than one are initialized, the behavior is undefined (6.9.2).

What an awkward paragraph, we can understand that GCC and VC allow "tentative definition" during the entire program compilation process, rather than a single "translation unit" within.

Then we can understand the previous two int a does not error the scene. The GCC VC sees such uninitialized variables as extern rather than define.

It is also understandable that if we add the initialization value:

int a = 0;int a = 0;int main (void) {    return 0;}   

You will get an error:

?  T  cc t1.cppt1.cpp:5:5:error:redefinition of ' a ' int A;    ^./t1.h:4:5: note:previous definition is hereint A;    ^t1.cpp:6:5:error:redefinition of ' a ' int A; ^./t1.h:4:5: note:previous definition is hereint a ; ^2 errors generated.         

Combined with the definition of tentative definition, it is not difficult to understand.

Here, the attentive reader may find that our tentative definition here is confined to the C language, yes. C + + does not endorse this concept, putting all int A; Treated as a variable definition. So, if you use C + +, these will all become redefinition or duplicate symbol.

Spit Groove: A seemingly simple problem, look up the information of the day, the extension of so many concepts, just thoroughly understand, I really learned C (⊙o⊙)?

The problem of defining global variables in the C language header file

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.