如何使用extern在源文件之间共享变量?

我知道C中的全局变量有时会有extern关键字。 什么是extern变量? 什么是宣言? 它的范围是什么?

这与在源文件中共享变量有关,但它是如何精确地工作的? 我在哪里使用extern


使用extern ,只有当您正在构建的程序由多个源文件链接在一起时才相关,其中一些定义的变量(例如,源文件file1.c需要在其他源文件(如file2.c引用) file2.c

理解定义变量和声明变量之间的区别非常重要:

  • 当编译器被告知存在一个变量(这是它的类型)时声明一个变量; 它不会在该点为该变量分配存储空间。
  • 当编译器为变量分配存储空间时定义一个变量。
  • 你可以多次声明变量(尽管一次就足够了); 您只能在给定范围内定义一次。 变量定义也是一个声明,但并非所有的变量声明都是定义。

    声明和定义全局变量的最佳方法

    尽管还有其他的方法,但声明和定义全局变量的干净可靠的方法是使用头文件file3.h来包含变量的extern声明。 标题包含在一个定义变量的源文件中,并由所有引用该变量的源文件包含。 对于每个程序,一个源文件(并且只有一个源文件)定义该变量。 同样,一个头文件(并且只有一个头文件)应该声明该变量。

    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++);
    }
    

    这是使用它们的最佳方式。


    接下来的两个文件完成prog1的源代码:

    请注意,我在标题中的函数声明前面使用关键字extern (例如,在prog1.h中所示),以匹配标题中变量声明前面的extern 。 很多人不喜欢在功能前面使用extern , 编译器不关心 - 最终,只要你一致,我也不会。

    prog1.h

    extern void use_it(void);   // "extern" is optional here; see note above
    extern int increment(void); // "extern" is optional here; see note above
    

    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使用prog1.cfile1.cfile2.cfile3.hprog1.h

  • 方针

    规则只能由专家打破,只有很好的理由:

  • 一个头文件只包含变量的extern声明 - 永远不会有static或非限定变量定义。
  • 对于任何给定的变量,只有一个头文件声明它(SPOT - 单点实例)。
  • 源文件永远不会包含变量的extern声明 - 源文件始终包含声明它们的(唯一)标题。
  • 对于任何给定的变量,只有一个源文件定义该变量,最好是初始化它。 (尽管没有必要明确地初始化为零,但它没有坏处并且可以做一些好处,因为程序中只能有一个特定全局变量的初始化定义)。
  • 定义变量的源文件还包含头部以确保定义和声明一致。
  • 函数应该永远不需要使用extern声明一个变量。
  • 尽可能避免全局变量 - 使用函数。
  • 如果你不是一个有经验的C程序员,你可以(也许应该)在这里停止阅读。

    这个答案的源代码和文本在src / so-0143-3204子目录中的GitHub的SOQ(Stack Overflow Questions)存储库中可用。

    不是很好的定义全局变量的方法

    使用一些(实际上是很多)C编译器,你也可以避开所谓的变量的'通用'定义。 'Common'是指Fortran中用于在源文件之间共享变量的一种技术,使用(可能命名为)COMMON块。 这里发生的是,许多文件中的每一个都提供了变量的暂定义。 只要不超过一个文件提供了初始化定义,那么各种文件最终将共享该变量的通用单一定义:

    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); }
    

    这种技术不符合C标准的字母和“一个定义规则”,但C标准将其列为其一个定义规则的常见变体。 因为这种技术并不总是被支持的,所以最好避免使用它,特别是如果你的代码需要可移植的话。 使用这种技术,你也可以结束无意的类型双关。 如果其中一个文件声明idouble而不是int ,那么C的类型不安全的连接器可能不会发现该不匹配。 如果你在64位intdouble的机器上,你甚至不会收到警告; 在具有32位int和64位double ,您可能会收到关于不同大小的警告 - 链接器将使用最大的大小,正如Fortran程序将采用任何常见块的最大大小一样。

    这在信息附录J的C标准中作为一个通用扩展提到:

    J.5.11多个外部定义

    对象的标识符可能有多个外部定义,有或没有明确使用关键字extern; 如果定义不一致,或者多于一个被初始化,则行为是不确定的(6.9.2)。


    接下来的两个文件完成了prog2的源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使用prog2.cfile10.cfile11.cfile12.cprog2.h

  • 警告

    正如我在这里的评论中指出的那样,正如我在回答类似问题时所指出的那样,对全局变量使用多个定义会导致未定义的行为,这是标准的说“任何事情都可能发生”的方式。 可能发生的事情之一是该程序按照您的预期行事; J.5.11大概说,“你可能比你应得的幸运更多”。 但是一个依赖extern变量的多重定义的程序 - 无论是否使用明确的“extern”关键字 - 都不是严格符合要求的程序,并且不能保证在任何地方都能正常工作。 等同:它包含一个可能会或可能不会显示的错误。

    违反准则

    faulty_header.h

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

    注1:如果标题定义了不带extern关键字的变量,则包含标题的每个文件都会创建该变量的临时定义。

    broken_header.h

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

    注2:如果头文件定义并初始化变量,则给定程序中只有一个源文件可以使用头文件。

    seldom_correct.h

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

    注3:如果头文件定义了一个静态变量(有或没有初始化),那么每个源文件最后都有它自己的'全局'变量的私有版本。

    例如,如果变量实际上是一个复杂的数组,那么这会导致代码的极度重复。 它可以非常偶然地是达到某种效果的明智方式,但这是非常不寻常的。


    概要

    使用我首先展示的标题技术。 它工作可靠,无处不在。 请特别注意,声明global_variable的头文件包含在每个使用它的文件中 - 包括定义它的文件。 这确保了一切都是自洽的。

    声明和定义功能也有类似的问题 - 类似的规则适用。 但问题特别是关于变量,所以我只保留了变量的答案。

    (完整的程序使用函数,因此函数声明已悄悄进入。我在头文件中的函数声明前使用关键字extern来匹配头文件中变量声明前面的extern 。许多人不希望在函数前面使用extern ,编译器不关心 - 最终,只要你一致,我也不会。)

    原答复结束

    如果你不是一个有经验的C程序员,你可能应该停止阅读这里。


    晚大加法

    避免代码复制

    有时(并且合法地)提出关于'头文件中的声明,源文件中的定义'机制的一个问题是有两个文件要保持同步 - 头文件和源文件。 通常会跟踪观察,可以使用宏来使头部承担双重任务 - 通常是声明变量,但是在包含头部之前设置特定宏时,它会定义变量。

    另一个问题可能是变量需要在许多“主程序”中的每一个中定义。 这通常是一个虚假的关注; 您可以简单地引入一个C源文件来定义变量并将生成的目标文件与每个程序链接起来。

    典型的方案是这样工作的,使用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++);
    }
    

    接下来的两个文件完成prog3的源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使用prog3.cfile1a.cfile2a.cfile3a.hprog3.h

  • 变量初始化

    所示的这个方案的问题是它不提供全局变量的初始化。 使用C99或C11和宏的可变参数列表,您可以定义一个宏来支持初始化。 (使用C89并且不支持宏中的可变参数列表,没有简单的方法来处理任意长的初始化程序。)

    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 });
    

    反转#if#else块的内容,修复由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;
    }
    

    显然,古怪的结构的代码不是你通常写的,但它说明了这一点。 第二次调用INITIALIZER的第一个参数是{ 41 ,剩下的参数(在这个例子中是单数)是43 } 。 如果没有C99或对宏的可变参数列表的类似支持,则需要包含逗号的初始化程序非常成问题。

    每个Denis Kniazhev file3b.h包含正确的头文件file3b.h (而不是fileba.h


    接下来的两个文件完成了prog4的源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使用prog4.cfile1b.cfile2b.cprog4.hfile3b.h

  • 标头卫兵

    任何头文件都应该受到保护以防止重新加入,所以类型定义(enum,struct或union类型或typedef通常)不会导致问题。 标准技术是将头部的主体包裹在头部守卫中,例如:

    #ifndef FILE3B_H_INCLUDED
    #define FILE3B_H_INCLUDED
    
    ...contents of header...
    
    #endif /* FILE3B_H_INCLUDED */
    

    标题可能间接包含两次。 例如,如果file4b.h包括file3b.h对于未示出的类型定义,并file1b.c需要使用两个头file4b.hfile3b.h ,那么你有一些棘手的问题需要解决。 显然,你可能会修改头文件列表来包含file4b.h 。 但是,您可能没有意识到内部依赖关系 - 并且代码应该在理想情况下继续工作。

    此外,它开始变得棘手,因为在包含file3b.h以生成定义之前,您可能会包含file4b.h ,但file3b.h上的正常头防护将防止头被重新包含。

    因此,您最多需要包含file3b.h的主体一次用于声明,最多一次用于定义,但您可能需要同时使用单个翻译单元(TU - 源文件和它使用的标头的组合) 。

    多变量定义包含

    但是,这可以通过一个不太无理的限制来完成。 我们来介绍一组新的文件名:

  • external.h用于EXTERN宏定义等。
  • file1c.h来定义类型(值得注意的是, struct oddballoddball_struct的类型)。
  • file2c.h来定义或声明全局变量。
  • file3c.c定义了全局变量。
  • file4c.c ,它只是使用全局变量。
  • file5c.c这表明你可以声明并定义全局变量。
  • file6c.c这表明你可以定义然后(试图)声明全局变量。
  • 在这些例子中, file5c.cfile6c.c直接包含头文件file2c.h几次,但这是显示机制起作用的最简单的方法。 这意味着如果标题间接包含两次,它也是安全的。

    这项工作的限制是:

  • 定义或声明全局变量的头文件本身可能不定义任何类型。
  • 紧接在包含应定义变量的标头之前,您需要定义宏DEFINE_VARIABLES。
  • 定义或声明变量的头部具有程式化的内容。
  • 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; }
    

    下一个源文件完成了prog5prog6prog7的源代码(提供了一个主程序):

    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使用prog5.cfile3c.cfile4c.cfile1c.hfile2c.hexternal.h
  • prog6使用prog5.cfile5c.cfile4c.cfile1c.hfile2c.hexternal.h
  • prog7使用prog5.cfile6c.cfile4c.cfile1c.hfile2c.hexternal.h

  • 该方案避免了大多数问题。 如果定义变量的头文件(例如file2c.h )包含在另一个定义变量的头文件(比如file7c.h )中,则只会遇到问题。 除了“不这样做”之外,没有一种简单的方法。

    您可以通过将file2c.h修改为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 */
    

    问题变成'如果标题包含#undef DEFINE_VARIABLES ?' 如果你从头文件中忽略了这些,并用#define#undef包装了任何定义的调用:

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

    在源代码中(所以头文件不会改变DEFINE_VARIABLES的值),那么你应该干净。 要记住写出额外的行是一件令人讨厌的事情。 另一种可能是:

    #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 */
    

    这有点令人费解,但似乎是安全的(使用file2d.h ,在file2d.h没有#undef DEFINE_VARIABLES 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; }
    

    接下来的两个文件完成了prog8prog9的源代码:

    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使用prog8.cfile7c.cfile9c.c
  • prog9使用prog8.cfile8c.cfile9c.c

  • 但是,这些问题在实践中相对不太可能发生,特别是如果您采取标准建议

    避免全局变量


    这个博览会是否遗漏了什么?

    自白:这里概述的“避免重复代码”方案是因为问题影响到我工作的一些代码(但不拥有),并且对答案的第一部分中概述的方案非常担心。 然而,最初的方案只留下两个地方进行修改,以使变量定义和声明保持同步,这是跨越代码库分布的外部变量声明向前迈出的一大步(当总共有数千个文件时,这非常重要) 。 但是,名称为fileNc.[ch] (加上external.hexterndef.h )的文件中的代码表明可以使其工作。 显然,创建头文件生成器脚本并不难,因为它为您提供了定义和声明头文件的变量的标准化模板。

    注意这些玩具程序只有足够的代码来使它们变得有趣。 这些例子中的重复可以被删除,但并不是为了简化教学解释。 (例如: prog5.cprog8.c之间的区别是包含的其中一个头文件的名称,可以重新组织代码,以便不重复main()函数,但它会隐藏更多比它显示的要多。)


    一个extern变量是一个在另一个翻译单元中定义的变量的声明(由于sbi的更正)。 这意味着变量的存储被分配在另一个文件中。

    假设你有两个.c -files test1.ctest2.c 。 如果你定义了一个全局变量int test1_var;test1.c ,你想在test2.c访问这个变量,你必须使用extern int test1_var;test2.c

    完整的样本:

    $ 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
    

    Extern是用于声明变量本身驻留在另一个翻译单元中的关键字。

    因此,您可以决定在翻译单元中使用变量,然后从另一个变量单元访问变量,然后在第二个变量单元中声明它为extern,并且符号将由链接程序解析。

    如果你不把它声明为extern,你会得到2个变量,它们的名字相同但是完全不相关,并且有多个变量定义的错误。

    链接地址: http://www.djcxy.com/p/43371.html

    上一篇: How do I use extern to share variables between source files?

    下一篇: Haskell do clause with multiple monad types