zoukankan      html  css  js  c++  java
  • [C]#include和链接

    概述

    对于刚接触C语言的同学来说,通常对“在文件中用#include预处理操作符引入文件”和“编译时链接多个文件”这两个操作会有所混淆,这个文章主要为了解析一下它们的区别。

    #include预处理操作符

    对于此类操作,你可以在C语言预处理机制上去理解,预处理,顾名思义是编辑器在编译前进行的一系列操作,例如把预定义常量替换成字面量等等,具体可以去参考一下编译器对#define操作符的处理过程。

    对于#include,实际上可以理解成PHP的include(如果你是先学PHP,再学C的同学),它实际上只是把文件引用进来,被引用文件被视为引用文件的一部分,文件作用域适用于这个文件

    1.在文件a.h中声明了一个变量,a.h被b.c引用进来,这时a.h相当于b.c的一部分,所以b.c具备了a.h声明的变量

    a.h:

    int foo = 1024;

    b.h

    #include <stdio.h>
    #include "a.h"int main(void)
    {
        printf("%d
    ", foo);//输出1024
    }

    用编译器直接编译b.h,无需链接a.h,因为a.h已经被引入了:

    gcc -std=gnu99   b.c -o b

    2.为了证明被引入的文件会被视为跟引入文件一体这个事实,再用下面这个示例说明一下,b.c引入头文件a.h,a.h包含一个static变量,c.c包含试图访问a.h的变量的代码,但是c.c不引入a.h,而是编译时跟b.c链接:

    我们先来看看正确的示范,首先不把foo声明为static编译程序,此时实际上是b.c和c.c相链(b.c包含了a.h)

    a.h:

    int foo = 1024;

    b.h:

    #include <stdio.h>
    #include "a.h"
    
    extern void test(void);
    int main(void)
    {
        printf("b:foo:%d
    ", foo);
        //test in c.c
        test();
    }

    c.c

    #include <stdio.h>
    
    extern int foo;
    void test(void)
    {
        printf("c:foo:%d
    ", foo);
    }

    编译程序:

    gcc -std=gnu99  b.c c.c -o b

    运行输出:

    b:foo:1024
    c:foo:1024

    再来看看把头文件变量声明为static后的影响,此时把foo声明为static:

    static int foo = 1024;

    再次编译可见发现报错:

    # gcc -std=gnu99 -trigraphs  b.c c.c -o b
    /tmp/cc8ojf4Q.o: In function `test':
    c.c:(.text+0x6): undefined reference to `foo'
    collect2: error: ld returned 1 exit status

    这是因为static具有文件作用域,b.c和c.c不视为同一个文件,而a.h和b.c则视为同一个文件;

    可以看看以下示例,更进一步说明了这一点,a.h声明的常量又或者变量,都可以在b.c访问到,通过链接形式的c.c访问foo和BAR则不行:

    a.h:

    #define BAR 256
    static int foo = 1024;

    b.h:

    #include <stdio.h>
    #include "a.h"
    
    int main(void)
    {
        printf("b:bar:%d
    ", BAR);//输出256
        printf("b:foo:%d
    ", foo);//输出1024
    }
  • 相关阅读:
    C#输出JS代码封装类Alart
    我的汇编学习之路(2)win8(64位)下安装debug
    .NET使用一般处理程序生成验证码
    ?运算符(null合并运算符)和三木运算符
    讲解:小菜鸟自制的.NET实体类生成器
    我的汇编学习之路(1)进制转换
    未来
    callee,caller区别
    string::size_type
    ubuntu 12.04 LTS u盘安装
  • 原文地址:https://www.cnblogs.com/yiyide266/p/11673178.html
Copyright © 2011-2022 走看看