c/c++中extern关键字详解

.h作用:

  头文件.h用于编写变量和函数的声明,对用户来说起到一个接口手册和说明的作用。在编译过程的预编译阶段,会将所有的#include原封不动的在原地展开。因此在利用makefile的make时候如果只是修改了.h头文件,利用make编译的时候不会进行增量编译,因为.h对应的.cpp或者.c并没有改变。需要单独删除.h对应的.o文件再进行make。

编译过程:

编译过程分为:

  1. 预编译阶段:作用:对源文件中的宏进行展开,对#include展开等等。命令:gcc -E test.c -o test.i
  2. 编译:将展开后的源文件编译成汇编文件(汇编语言)命令:gcc -S test.i -o test.s
  3. 汇编:将汇编文件编译成01机器码的.o文件  命令:as test.s -o test.o
  4. 链接:将所有的.o文件链接(链接引用库等等)成一个可执行程序.exe文件。gcc test.o test2.o -o test

编译过程示例:

//lib.h
int addTwo(int a, int b);

//lib.c
int addTwo(int a, int b)
{
    return a+b;
}
//main.c
#include <stdio.h>
#include "lib.h"
int main()
{
    int sum = addTwo(1, 2);
    printf("sum=%d\n", sum);  
    return 0;
}

gcc -E main.c -o main.i进行预编译:

可以看到stdio.h展开了好几百行到main.c文件中,lib.h将函数的声明展开到了源文件中。

最后进行链接的命令是:

gcc main.o lib.o -o main

生成可执行程序。编译命令中没有.h文件,因为在预编译过程中已经将所有的.h文件都展开到了源文件中了。

extern简述:

  extern是计算机语言中的一个关键字,可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义。

  每一个c文件或者cpp文件最后都会编译为一个.o文件或者.obj文件,最后将所有的.o或.obj文件链接起来组成一个可执行.exe文件。在其他模块的意思是指在链接的时候从其他.o或者.obj文件中找extern变量的定义。

extern代码示例:

对变量而言,如果你想在本源文件(例如文件名A)中使用另一个源文件(例如文件名lib)的全局变量(假设为int gVar),方法有2种:

一、在文件A中声明extern int gVar,且不包含lib的全局变量gVar。表示编译器在链接的时候在另外模块中寻找gVar的定义。即在lib.o中寻找。

//lib.h
int gVar = 3;

//lib.c
#include "lib.h"
//A.c
int main()
{
    extern int gVar;
    printf("gVar=%d\n", gVar);
}

程序正常输出3;

编译链接的时候需要将lib.o加上:gcc main.c lib.c -o main

 

二、在lib.h文件中声明全局变量extern int gVar,在lib.c中定义变量gVar。文件A中包含这个lib.h,即可直接使用gVar变量了。

考虑下面这种情况:

//lib.h
int gVar=3;
int addTwo(int a, int b);

//lib.c
#include "lib.h"
int addTwo(int a, int b)
{
    return a+b;
}
//A.h
#include "lib.h"

//A.c
#include "A.h"

int main()
{
    int sum = addTwo(1,2);
    printf("sum=%d\n", sum);
    printf("%d\n", gVar);
    return 0;
}

当进行gcc lib.c A.c -o A的时候会报错。

原因是在链接的过程中发现重复定义了变量gVar:

修改如下:

//lib.h
extern int gVar;  //声明全局变量 extern int gVar = 3;是定义
int addTwo(int a, int b);

//lib.c
#include "lib.h"
int gVar = 3; //定义变量
int addTwo(int a, int b)
{
    return a+b;
}
//A.h
#include "lib.h"

//A.c
#include "A.h"

int main()
{
    int sum = addTwo(1,2);
    printf("sum=%d\n", sum);
    printf("%d\n", gVar);
    return 0;
}

程序正常输出。

因为在lib.h中只是声明了gVar且为extern,所以在A.o和lib.o的链接过程中,A.o使用的gVar会到其他模块lib.o中寻找gVar的定义,找到为3。

实际代码会更加复杂,此处几个实例简单地剥离来讨论。

posted @ 2020-01-29 17:17  只取一瓢饮  阅读(997)  评论(0编辑  收藏  举报