关于C#:如何使用extern在源文件之间共享变量?

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

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

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


使用extern只有在您正在构建的程序中才有意义。由多个链接在一起的源文件组成,其中例如,在源文件file1.c中定义的变量需要在其他源文件中引用,如file2.c。好的。

理解定义变量并声明变量:好的。

  • 当编译器得知变量存在(这是它的类型);它不分配在该点存储变量。
  • 当编译器为指定的变量。

您可以多次声明一个变量(尽管一次就足够了);在给定范围内只能定义一次。变量定义也是一个声明,但不是所有变量声明是定义。好的。声明和定义全局变量的最佳方法

声明和定义全局变量的干净、可靠的方法是使用包含变量的extern声明的头文件。好的。

头包含在定义变量的源文件中以及引用变量的所有源文件。对于每个程序,一个源文件(并且只有一个源文件)定义变量。同样,一个头文件(并且只有一个头文件)应该声明变量。头文件非常重要;它可以在独立的tus(翻译单元-思考源文件)并确保一致性。好的。

虽然还有其他方法,但这种方法很简单,可靠。由file3.hfile1.cfile2.c证明:好的。文件3.h

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

文件1.C

1
2
3
4
5
6
7
#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++; }

文件2.C

1
2
3
4
5
6
7
8
9
#include"file3.h"
#include"prog1.h"
#include <stdio.h>

void use_it(void)
{
    printf("Global variable: %d
"
, global_variable++);
}

这是声明和定义全局变量的最佳方法。好的。

接下来的两个文件完成了prog1的源文件:好的。

所示的完整程序使用函数,因此函数声明蹑手蹑脚地进来。C99和C11都要求在函数之前声明或定义它们使用(而C90没有,原因很好)。我在头中的函数声明前面使用关键字extern。为了一致性--在变量前面匹配extern。头中的声明。许多人不喜欢在功能前使用extern。声明;编译器不在乎——最终,我也不在乎只要您是一致的,至少在源文件中是一致的。好的。Pro 1.H

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

前C

1
2
3
4
5
6
7
8
9
10
11
12
13
#include"file3.h"
#include"prog1.h"
#include <stdio.h>

int main(void)
{
    use_it();
    global_variable += 19;
    use_it();
    printf("Increment: %d
"
, increment());
    return 0;
}
  • prog1使用prog1.cfile1.cfile2.cfile3.hprog1.h

文件prog1.mk仅为prog1的makefile。它将与大多数版本的make一起工作,该版本自转弯时起生产。千禧年。它不是专门与GNU制造联系在一起的。好的。PROF1.MK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 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}

指南

只有专家才能打破规则,而且必须有充分的理由:好的。

  • 头文件只包含extern变量声明-从不static或非限定变量定义。
  • 对于任何给定的变量,只有一个头文件声明它(spot-单点真理)。
  • 源文件从不包含变量的extern声明-源文件始终包含声明它们的(唯一)头文件。
  • 对于任何给定的变量,只有一个源文件定义变量,最好也初始化它。(尽管没有必要显式初始化为零,没有伤害,可以做点好事,因为一个特定的程序中的全局变量)。
  • 定义变量的源文件还包括确保定义和声明一致。
  • 函数不需要使用extern声明变量。
  • 尽可能避免使用全局变量-改用函数。

此答案的源代码和文本在我的SOQ(堆栈溢出问题)Github上的存储库SRC/SO-0143-3204标准子目录。好的。

如果你不是一个经验丰富的C程序员,你可以(也许应该)停止阅读。好的。定义全局变量的方法不太好

有了一些(实际上是许多)C编译器,您就可以摆脱也调用了变量的"common"定义。这里的"common"是指Fortran中用于共享的技术。源文件之间的变量,使用(可能已命名)公共块。这里所发生的是,许多文件中的每一个都提供了变量的定义。只要不超过一个文件提供初始化定义,然后,各种文件最终共享了变量:好的。文件10C

1
2
3
4
5
#include"prog2.h"

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

void inc(void) { i++; }

文件11C

1
2
3
4
5
#include"prog2.h"

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

void dec(void) { i--; }

文件12C

1
2
3
4
5
6
7
#include"prog2.h"
#include <stdio.h>

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

void put(void) { printf("i = %d
"
, i); }

此技术不符合C标准的字母和"一个定义规则"-这是官方未定义的行为:好的。

J.2 Undefined behavior

Ok.

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).

Ok.

§6.9 External definitions ?5

Ok.

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)

Ok.

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

Ok.

然而,C标准也在资料性附录J中将其列为常见的扩展。好的。

J.5.11 Multiple external definitions

Ok.

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).

Ok.

因为不总是支持这种技术,所以最好避免使用它,特别是当您的代码需要可移植时。使用这种技术,您也可以以无意的类型结束双关语。如果其中一个文件声明idouble而不是int,C的类型不安全的链接器可能不会发现不匹配。如果你在一台64位intdouble的机器上,你甚至不会得到一个警告;在一台32位int和64位double的机器上,你会可能会收到关于不同大小的警告-链接器会使用最大的大小,就像Fortran程序任何公共块的最大大小。好的。

接下来的两个文件完成了prog2的源文件:好的。PrO2

1
2
3
extern void dec(void);
extern void put(void);
extern void inc(void);

丙二丙

1
2
3
4
5
6
7
8
9
10
11
12
#include"prog2.h"
#include <stdio.h>

int main(void)
{
    inc();
    put();
    dec();
    put();
    dec();
    put();
}
  • prog2使用prog2.cfile10.cfile11.cfile12.cprog2.h

警告

正如我在这里的评论中提到的,以及我对类似的问题,使用多个全局变量的定义导致未定义的行为(J.2;§6.9),这是标准的说法"任何事情都可能发生"。可能发生的事情之一是程序的行为和您的一样期待;J.5.11说,大约,"你可能更幸运比你应得的多"。但是一个依赖外部变量的多个定义的程序-带或不带显式"extern"关键字-不是严格的符合程序,不保证在任何地方工作。等价的:它包含一个可能或可能不显示自己的bug。好的。违反准则

当然,有很多方法可以打破这些准则。有时,可能有一个很好的理由违反指导方针,但是这种场合是极不寻常的。好的。福斯提字母名称(P)说明1:如果主定义的变量不包括EDOCX1 0。Then each file that includes the header creates a tentative definition从变量。As noted previously,this will often work,but the C standard does not确保这是工作。好的,好的。断裂之王字母名称(P)说明2:If the header defines and initializes the variable,they only1 Source file in a given program can use the header.因为头头是分享信息的主要渠道,所以它是一个比特沉默。To create one that can only be used 11.好的,好的。塞尔顿字母名称(P)说明3:If the header defines a static variable(with or without)Initialization,they each source file ends up with its own private全球变量的版本。好的,好的。(P)如果变量实际上是一个完整的阵列,例如,这可能会导致To extreme duplication of code.It can,very occasionally,be a敏感的方式来实现一些效果,但这是非常不寻常的。好的,好的。摘要(P)先用我的头技术It works reliably and everywhere.注意,特别是,主宣布以东X1为英文字母Included in every file that used it-including the one that defines it.This ensures that everything is self-consistent.好的,好的。(P)类似的关注与声明和定义的功能-Analogous Rules Apply.But the question was about variables specifically,so I've kept theAnswer to variables only.好的,好的。原创答案的结尾(P)如果你不是一个经验C程序,你应该停止阅读在这里。好的,好的。(P)Late Major Addition好的,好的。避免代码复制(P)Some concern that is sometimes(and legislately)raised about theDeclarations in Headers,Definitions in Source'Mechanism describedThere is that there are two files to be kept synchronized-the headerand the source.This is usually followed up with an observations that aMacro can be used so the header serves double duty-normally宣布变量,但当一个特定的宏观在设定之前Header is included,it defines the variables instead.好的,好的。(P)另一个关注可能是,变量需要被定义为a number of"main programs".这通常是一个土豆的问题;你Can simply introduce a c source file to define the variables and linkThe object file produced with each of the programs.好的,好的。(P)一个类型的计划工作类似于此,使用原始的全球变量伊留斯特好的,好的。牛排字母名称排骨字母名称页:1字母名称(P)下一份两份文件完成了EDOCX1的来源好的,好的。方案3.h字母名称方案3.c字母名称

  • 爱德华X1

初始变量(P)The problem with this scheme as shown is that it does not provide for3.Initialization of the global variable.与C99或C11和可变ArgumentLists 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.)好的,好的。立体字母名称(P)Reverse contents of EDOCX1 theocx1 plus 10 welcxy and EDOCX1 English 11 locks,fixing bug identified byDenis Kniazhev好的,好的。页:1字母名称牛排字母名称(P)Clearly,the code for the oddball structure is not what you'd normallyWrite,but it illustrates the point.The first argument to the second援引EDOCX1的英文字母12是EDOCX1的英文13和继续争论这个例子中的单数是英文字母14。无C99或类似支持For variable argument lists for macros,initializers that need to计算商品是一个很大的问题。好的,好的。(P)Correct Header EDOCX1 English 15 included(Instead of EDOCX1)Denis Kniazhev好的,好的。(P)下一份两份文件完成了EDOCX1的来源好的,好的。 prog4.h

1
2
3
extern int increment(void);
extern int oddball_value(void);
extern void use_them(void);

prog4.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include"file3b.h"
#include"prog4.h"
#include <stdio.h>

int main(void)
{
    use_them();
    global_variable += 19;
    use_them();
    printf("Increment: %d
"
, increment());
    printf("Oddball:   %d
"
, oddball_value());
    return 0;
}
  • 使用prog4.cprog4file1b.cfile2b.cprog4.hfile3b.h

标题:

任何头应该保护对reinclusion,所以那型 (枚举的定义,struct或联盟的类型或类型,一般做标注) 因为问题。冰的标准技术对身体的包裹 头一集控球后卫如: </P >好。

1
2
3
4
5
6
#ifndef FILE3B_H_INCLUDED
#define FILE3B_H_INCLUDED

...contents of header...

#endif /* FILE3B_H_INCLUDED */

"头两次indirectly included可能会问。例如,如果 file4b.h包括file3b.h为A型的定义,这是不是shown; 和file1b.c需求到使用都file4b.hfile3b.h头,然后 你有一些更多的resolve狡猾的问题。明确的,你可能revise 狡猾的头是file4b.hto include。但是,你可能问的注释 美国《国内dependencies感知和的代码应该,ideally; 继续到工作。 </P >好。

进一步的,它开始对山羊,狡猾的,因为你可能file4b.hinclude 在包括file3b.hto Generate的定义,但正常的 标题:在file3b.h会reincluded头被预防的。 </P >好。

所以,你需要TO INCLUDE身体部file3b.h实习生最次的方法 declarations,和在最为定义一次,但你可能需要维持 在一个单一的翻译单元(TU)的组合,一个源文件和 它的头域的使用)。 </P >好。 包含与多变量的定义

但是,它可以让做的太受A标注不当的约束。 "让一个新的集并部文件名称: </P >好。

  • external.h外部定义的宏,等。
  • file1c.h(特别是通过对define类型,struct oddballoddball_struct类型)。
  • file2c.h到define或DECLARE全局变量。
  • 这defines file3c.c全局变量。
  • file4c.c这简单的使用全局变量。
  • file5c.c"节目,你可以define DECLARE和当时的全局变量。
  • file6c.c"节目,你才可以define(DECLARE attempt到全局变量)。

在这些例子中,file5c.cfile6c.c直接include the头 file2c.h个时代,但那是simplest方式到我的表演 机构的工作。它意味indirectly如果头是included 两次,信息安全也会祈祷。 </P >好。

"限制这到工作是: </P >好。

  • 该部分界定或申报了全局变量本身可能不是 define任何类型。
  • 立即在你那一头就应该define变量; 你的define _ define宏观变量。
  • 《申报》界定或头部有stylized变量的内容。
  • external.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /*
    ** This header must not contain header guards (like  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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    /* 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

    1
    2
    3
    4
    5
    #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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include"file2c.h"
    #include <stdio.h>

    void use_them(void)
    {
        printf("Global variable: %d
    "
    , global_variable++);
        oddball_struct.a += global_variable;
        oddball_struct.b -= global_variable / 2;
    }

    file5c.c

    1
    2
    3
    4
    5
    6
    7
    #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

    1
    2
    3
    4
    5
    6
    7
    #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; }

    下一completes源文件的源(主程序提供一prog5),prog6prog7: </P >好。 prog5.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include"file2c.h"
    #include <stdio.h>

    int main(void)
    {
        use_them();
        global_variable += 19;
        use_them();
        printf("Increment: %d
    "
    , increment());
        printf("Oddball:   %d
    "
    , oddball_value());
        return 0;
    }
    • 使用prog5.cprog5file3c.cfile4c.cfile1c.hfile2c.hexternal.h
    • 使用prog5.cprog6file5c.cfile4c.cfile1c.hfile2c.hexternal.h
    • 使用prog5.cprog7file6c.cfile4c.cfile1c.hfile2c.hexternal.h

    本方案避免很多问题。你只运行到一个问题,如果A 标题是defines变量(如file2c.h)冰included村 另一个header(说file7c.h)是defines变量。是不是有一个 简单的方式比其他方位,是"不做它"。 </P >好。

    你可以不完全的问题,进行全面的revising file2c.h到村 file2d.h: </P >好。 file2d.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /* 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 */

    "问题"应该成为"include #undef DEFINE_VARIABLES头吗?" 如果你是从omit头和包的任何invocation与界定 #define#undef: </P >好。

    1
    2
    3
    #define DEFINE_VARIABLES
    #include"file2c.h"
    #undef DEFINE_VARIABLES

    在源代码(SO的头域的值不会改变大学 DEFINE_VARIABLES),那么你应该问的清洁。它只是一个nuisance到冰 要记得写"辅助线。问:是否会替代 </P >好。

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

    externdef.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*
    ** This header must not contain header guards (like  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 */

    这是越来越convoluted A点,但表明是安全的(使用 file2d.h#undef DEFINE_VARIABLES与NO的file2d.h)。 </P >好。 file7c.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /* 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    /* 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    /* 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指南: </P >好。 Pro 8. C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include"file2d.h"
    #include <stdio.h>

    int main(void)
    {
        use_them();
        global_variable += 19;
        use_them();
        printf("Increment: %d
    "
    , increment());
        printf("Oddball:   %d
    "
    , oddball_value());
        return 0;
    }

    文件9C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include"file2d.h"
    #include <stdio.h>

    void use_them(void)
    {
        printf("Global variable: %d
    "
    , 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文件test1.ctest2.c。如果你在test1.c中定义了一个全局变量int test1_var;,你想在test2.c中访问这个变量,你必须在test2.c中使用extern int test1_var;

    完整样品:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    $ cat test1.c
    int test1_var = 5;
    $ cat test2.c
    #include <stdio.h>

    extern int test1_var;

    int main(void) {
        printf("test1_var = %d
    "
    , test1_var);
        return 0;
    }
    $ gcc test1.c test2.c -o test
    $ ./test
    test1_var = 5


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

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

    如果不将其声明为外部变量,则会得到两个同名但完全不相关的变量,以及变量的多个定义错误。


    我喜欢把外部变量看作是对编译器的承诺。

    当遇到extern时,编译器只能找到它的类型,而不能找到它的"所在位置",因此它无法解析引用。

    你在说,"相信我。在链接时,此引用将是可解析的。"


    extern告诉编译器相信您这个变量的内存是在别处声明的,因此它不会尝试分配/检查内存。

    因此,您可以编译一个引用外部的文件,但是如果没有在某个地方声明该内存,则不能链接该文件。

    对于全局变量和库很有用,但是很危险,因为链接器不进行类型检查。


    添加extern将变量定义转换为变量声明。查看这个线程,了解声明和定义之间的区别。


    extern的正确解释是您向编译器说明一些事情。您告诉编译器,尽管当前不存在,但链接器将以某种方式找到声明的变量(通常在另一个对象(文件))。然后,不管你是否有一些外部声明,链接器将是找到所有东西并将其组合在一起的幸运的人。


    在C语言中,文件中的一个变量,例如example.c是给定的局部作用域。编译器期望该变量的定义位于同一个文件example.c中,如果找不到该变量,则会引发错误。另一方面,函数在默认情况下具有全局范围。因此,您不必显式地提到编译器"look dude…您可以在这里找到这个函数的定义"。对于包含其声明的文件的函数来说就足够了。(实际调用头文件的文件)。例如,考虑以下两个文件:实例C

    1
    2
    3
    4
    5
    6
    #include<stdio.h>
    extern int a;
    main(){
           printf("The value of a is <%d>
    "
    ,a);
    }

    1、C

    1
    int a = 5;

    现在,当您使用以下命令将两个文件编译在一起时:

    步骤1)cc-o示例.c示例1.c步骤2)

    您得到以下输出:a的值<5>


    extern关键字用于将变量标识为全局变量。

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


    Linux下的gcc实现11

    main.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>

    int not_extern_int = 1;
    extern int extern_int;

    void main() {
        printf("%d
    "
    , not_extern_int);
        printf("%d
    "
    , extern_int);
    }

    编译和decompile:

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

    输出包含:

    1
    2
    3
    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

    系统V ABI规格更新11章解释了:"符号表"

    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.

    这是基本的行为给予externC标准变量。

    从现在的工作,它是在左翼做最终的项目,但extern安切洛蒂已经被提取的信息从源代码到目标文件。

    4.8在GCC的测试。

    C++内联变量17

    17在C + +,你可能想使用内联变量而不是外部的人,他们是简单的使用(可以定义只在头一次强大的(支持)和更多的constexpr)。湖:什么'是const静态均值在C和C + +?


    extern允许程序的一个模块访问程序的另一个模块中声明的全局变量或函数。通常在头文件中声明了外部变量。

    如果不希望程序访问变量或函数,可以使用static,它告诉编译器不能在该模块之外使用该变量或函数。


    extern简单的均值a是定义变量的地方(例如,在另一个文件)。


    1
    2
    3
    4
    5
    6
    7
    8
    9
                     declare | define   | initialize |
                    ----------------------------------

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

    声明不会分配内存(内存分配变量必须定义(定义)的通道。这只是另一个视图上简单的外部关键字。其他答案是真正伟大的。


    首先,extern关键字不用于定义变量,而是用于声明变量。我可以说extern是一个存储类,而不是数据类型。

    extern用于让其他C文件或外部组件知道这个变量已经在某个地方定义了。示例:如果您正在构建一个库,则无需强制在库本身的某个地方定义全局变量。库将直接编译,但在链接文件时,它会检查定义。


    extern是这样一个全first.c文件可以访问另一个second.c全球参数文件。

    这可以被externfirst.c头文件或任何文件的first.c包括。


    你要小心与xc8约declaring a变量在每一个相同的类型的文件你可以erroneously,,在一个文件中声明的东西intchar说在另一个。这可能导致腐败)的变量。

    这个问题是我在论坛的一些优雅的15年前的A系统*湖"www.htsoft.com http:/ /"所有showflat.php论坛/ / / / / / / 0的数18766 CAT / / 0 / / 0 # 18766页"

    但这似乎链接不再工作……

    所以我会很快;它试图解释;为使文件global.h.

    在它下面的声明

    1
    2
    3
    4
    5
    6
    7
    #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

    现在,在main.c文件

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

    本main.c均值的变量将被作为一个unsigned char

    现在在其他的文件包括global.h想简单它被作为一个外部的一个文件。

    1
    extern unsigned char testing_mode;

    但它会被作为一个unsigned char正确。

    旧论坛后可能解释这一位更适合。但这是一个真实的潜力gotcha当使用编译器这允许你声明一个变量在声明它的外部文件,然后作为一个不同的类型。问题与如果你说的是被测试_模式为另一个文件中。它会认为这是一个16位的无功和覆盖更多的潜在的一部分RAM,腐败的另一个变量。难调试!