C 如何使用extern在源文件之间共享变量?
我知道C中的全局变量有时有C 如何使用extern在源文件之间共享变量?,c,global-variables,extern,C,Global Variables,Extern,我知道C中的全局变量有时有extern关键字。什么是extern变量?宣言是什么样的?它的范围是什么 这与跨源文件共享变量有关,但这究竟是如何工作的呢?在哪里使用extern?extern是用于声明变量本身位于另一个转换单元中的关键字 因此,您可以决定在转换单元中使用一个变量,然后从另一个单元访问它,然后在第二个单元中声明它为extern,符号将由链接器解析 如果您不将其声明为extern,您将得到两个名称相同但完全不相关的变量,并且该变量的多个定义存在错误。一个extern变量是另一个翻译单元
extern
关键字。什么是extern
变量?宣言是什么样的?它的范围是什么
这与跨源文件共享变量有关,但这究竟是如何工作的呢?在哪里使用
extern
?extern是用于声明变量本身位于另一个转换单元中的关键字
因此,您可以决定在转换单元中使用一个变量,然后从另一个单元访问它,然后在第二个单元中声明它为extern,符号将由链接器解析
如果您不将其声明为extern,您将得到两个名称相同但完全不相关的变量,并且该变量的多个定义存在错误。一个
extern
变量是另一个翻译单元中定义的变量的声明(感谢sbi的更正)。这意味着变量的存储被分配到另一个文件中
假设您有两个.c
-文件test1.c
和test2.c
。如果您定义了一个全局变量inttest1\u var如果您想在test2.c
中访问此变量,必须使用extern int test1\u 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 = %d\n", test1_var);
return 0;
}
$ gcc test1.c test2.c -o test
$ ./test
test1_var = 5
$cat test1.c
int test1_var=5;
$cat test2.c
#包括
外部内部测试1_var;
内部主(空){
printf(“test1\u-var=%d\n”,test1\u-var);
返回0;
}
$gcc test1.c test2.c-o测试
美元/测试
test1_var=5
添加extern
将变量定义转换为变量声明。看看声明和定义之间的区别 extern告诉编译器相信您该变量的内存是在别处声明的,因此它不会尝试分配/检查内存
因此,您可以编译一个引用外部的文件,但如果内存没有在某处声明,则无法链接
对全局变量和库有用,但危险是因为链接器不进行类型检查。使用extern
仅在您正在构建的程序中相关
由链接在一起的多个源文件组成,其中
例如,在源文件file1.c
中定义的变量需要
在其他源文件中引用,例如file2.c
重要的是:
- 当编译器被告知
变量存在(这是它的类型);它不分配资源
此时变量的存储
- 当编译器为变量分配存储时,定义了一个变量
变量
可以多次声明变量(尽管一次就足够了);
在给定范围内只能定义一次。
变量定义也是一种声明,但不是所有变量
声明是定义
声明和定义全局变量的最佳方法
声明和定义全局变量的干净、可靠的方法是使用
包含变量的外部声明的头文件
标头包含在定义变量的一个源文件中
以及引用该变量的所有源文件。
对于每个程序,一个源文件(并且只有一个源文件)定义
变量
类似地,一个头文件(并且只有一个头文件)应该声明
变量
头文件至关重要;它可以在不同的服务器之间进行交叉检查
独立的TUs(翻译单元-思考源文件)并确保
一致性
尽管有其他方法可以做到这一点,但这种方法简单易行
可靠。
它可以通过file3.h
、file1.c
和file2.c
进行演示:
文件3.h
extern int全局变量;/*变量的声明*/
文件1.c
#包括此处提供的“file3.h”/*声明*/
#包括“prog1.h”/*函数声明*/
/*此处定义的变量*/
int全局_变量=37;/*根据声明检查定义*/
int增量(void){return global_variable++;}
文件2.c
#包括“file3.h”
#包括“prog1.h”
#包括
作废使用它(作废)
{
printf(“全局变量:%d\n”,全局变量++);
}
这是声明和定义全局变量的最佳方法
接下来的两个文件完成了prog1
的源代码:
显示的完整程序使用函数,因此函数声明
潜入。
C99和C11都需要先声明或定义函数,然后才能使用它们
使用了(而C90没有使用,原因很好)。
我在标题中的函数声明前面使用关键字extern
一致性-匹配变量前面的extern
标题中的声明。
许多人不喜欢在函数前面使用extern
声明;编译器不在乎——最终,我也不在乎
只要是一致的,至少在源文件中是一致的
项目1.h
extern void使用它(void);
外部内部增量(无效);
项目1.c
#包括“file3.h”
#包括“prog1.h”
#包括
内部主(空)
{
使用它();
全局_变量+=19;
使用它();
printf(“增量:%d\n”,增量());
返回0;
}
prog1
使用prog1.c
,file1.c
,file2.c
,file3.h
和prog1.h
文件prog1.mk
仅是prog1
的生成文件。
它将适用于从大约本回合开始生产的大多数版本的make
千禧年。
它不是专门与GNU Make绑定的
prog1.mk
指导方针
只有专家才能违反规则,而且必须有充分的理由:
- 头文件仅包含变量的
extern
声明-从不
静态
# 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}
#ifndef FILE3B_H_INCLUDED
#define FILE3B_H_INCLUDED
...contents of header...
#endif /* FILE3B_H_INCLUDED */
#define DEFINE_VARIABLES
#include "file2c.h"
#undef DEFINE_VARIABLES
#define HEADER_DEFINING_VARIABLES "file2c.h"
#include "externdef.h"
#include<stdio.h>
extern int a;
main(){
printf("The value of a is <%d>\n",a);
}
int a = 5;
#include <stdio.h>
int not_extern_int = 1;
extern int extern_int;
void main() {
printf("%d\n", not_extern_int);
printf("%d\n", extern_int);
}
gcc -c main.c
readelf -s main.o
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
#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
#define MAIN_C 1
#include "global.h"
#undef MAIN_C
extern unsigned char testing_mode;
declare | define | initialize |
----------------------------------
extern int a; yes no no
-------------
int a = 2019; yes yes yes
-------------
int a; yes yes no
-------------
//file foo_globals.h
#pragma once
#include "foo.h" //contains definition of foo
#ifdef GLOBAL
#undef GLOBAL
#endif
#ifdef GLOBAL_FOO_IMPLEMENTATION
#define GLOBAL
#else
#define GLOBAL extern
#endif
GLOBAL Foo foo1;
GLOBAL Foo foo2;
//file main.cpp
#define GLOBAL_FOO_IMPLEMENTATION
#include "foo_globals.h"
//file uses_extern_foo.cpp
#include "foo_globals.h