• 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
    ", 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
    ", 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
    ", sum);
        printf("%d
    ", 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
    ", sum);
        printf("%d
    ", gVar);
        return 0;
    }

    程序正常输出。

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

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

  • 相关阅读:
    Java spring自查笔记
    C#设置IP地址 用WMI
    idea换成护眼色
    WPF布局的6种面板
    spring注解
    c# 播放mp3
    Python 提示 “No matching distribution found for MySQLdb”
    Python3链接数据库报错:Connection.__init__() takes 1 positional argument but 5 positional arguments (and 1 keywordonly argument) were given
    安装Mysql数据库及配置相关环境变量
    Python中文件命名的注意事项
  • 原文地址:https://www.cnblogs.com/jialin0x7c9/p/12240804.html
Copyright © 2020-2023  润新知