zoukankan      html  css  js  c++  java
  • 头文件的作用分析

    问题引入

    假设有一个C/C++语言项目,项目中包含了很多模块,每个模块中又包含了很多功能函数。对于这个项目,稍稍学习过编程知识的开发者都会将模块做成动态或者静态库。在动态或者静态库中,往往包含了很多头文件和源文件。现在思考一个问题,为什么需要头文件?似乎从开始学习编程开始老师就教导我们要写头文件和源文件,但是有没有认真思考过它们的作用?本篇来通过一个简单例子来简要分析一下头文件的作用。

    背景介绍

    为了简化问题,我们假设需要开发一个可执行项目,在这个项目中需要一个模块,这个模块中仅仅包含两个函数,它们的作用就是打印出传入的参数值。代码如下:

     1 #include <stdio.h>
     2 
     3 void test(int val)
     4 {
     5     printf("test : %d
    ", val);
     6 }
     7 
     8 void fun(int val)
     9 {
    10     printf("fun : %d
    ", val);
    11 }

    再增加main函数,代码如下:

    1 int main(int argc, char* argv[])
    2 {
    3     test(123);
    4     fun(456);
    5     return 0;
    6 }

    不划分模块

    最简单的情况就是将这个模块和main函数写在一个文件中,但是我们都知道这样做不但模块无法重用,同时也会给后面扩充功能带来繁重的工作。划分模块,可以将功能封装,隐藏实现细节,还可以更好的实现模块复用,并且独立模块间的低耦合也为了扩展升级提供了便利。

    将这个源文件编译:

    gcc -o nomodule main.c

    使用头文件

    加入头文件test.h,代码如下:

    1 #ifndef TEST_H_
    2 #define TEST_H_
    3 
    4 void test(int val);
    5 void fun(int val);
    6 
    7 #endif //TEST_H_

    修改main.c,代码如下:

    1 #include "test.h"
    2 
    3 int main(int argc, char* argv[])
    4 {
    5     test(123);
    6     fun(456);
    7     return 0;
    8 }

    重新编译

    gcc -o header main.c test.c

    执行程序,可以看到效果。再来看下头文件的作用,使用gcc -E来查看预处理的结果

    gcc -E test.c -o test.i

    查看test.i,关键的代码如下:

    1 # 1 "./test.h" 1
    2 
    3 void test(int val);
    4 void fun(int val);

    可以看到#include "test.h"被展开了,它的内容就是我们在头文件中写的两个函数声明。其实,这就是头文件的作用体现了,也就是说在test.c文件中将头文件中的内容加入了进来。可以再使用上述命令查看main.c文件,结果也是一样的。我们将i文件编译成o文件:

    1 gcc -c test.i -o test.o
    2 gcc -c main.i -o main.o

    然后将o文件编译成可执行程序:

    gcc -o header main.o test.o

    执行与上一节结果是一样的。你会不会有疑问?难道可以不用头文件?别急,我们继续。

    没有头文件

    是的,这次没有头文件。

    test.c中定义两个函数,内容省略。

    在main.c中,代码如下:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 void test(int);
     5 void fun(int);
     6 
     7 int main(int argc, char* argv[])
     8 {
     9     test(123);
    10     fun(456);
    11     return 0;
    12 }

    将test.c编译为目标文件o文件

    gcc -c test.c

    再将main.c编译为目标文件

    gcc -c main.c

    将两个目标文件链接为可执行程序

    gcc -o noheader main.o test.o

    执行与前两节是一样的。至此,可以完全看明白头文件的作用了,它在预处理期间就被展开了,然后嵌入到源文件当中。

    总结

    通过以上三种情况的分析可以看到头文件在编译链接过程中的作用,从编译链接的角度来说,不写头文件也是行得通的,只要你不怕写N多函数或者类的声明就行。其实,函数声明只是在生成目标文件(*.o)时产生一个符号,具体符号的使用是在链接期间绑定的,而不同的编译方式(静态编译或动态编译)绑定的时机也不相同,以后再详细介绍。

  • 相关阅读:
    数据可视化之DAX篇(二)Power BI中的度量值和计算列,你搞清楚了吗?
    数据可视化之DAX篇(一)Power BI时间智能函数如何处理2月29日的?
    数据可视化之powerBI技巧(二十四)Power BI初学者刚见的错误,帮你轻松处理
    数据可视化之powerBI技巧(二十三)Power BI可视化技巧,使用DAX自定义时间轴
    数据可视化之powerBI技巧(二十二)利用这个方法,帮你搞定Power BI"增量刷新"
    数据可视化之powerBI技巧(二十一)简单三个步骤,轻松管理你的Power BI度量值
    数据可视化之powerBI技巧(二十)采悟:创建度量值,轻松进行分组统计
    数据可视化之powerBI技巧(十九)DAX作图技巧:使用度量值动态分组和配色
    数据可视化之powerBI技巧(十八)Power BI动态技巧:动态显示列和度量值
    JavaScript isFinite() 函数
  • 原文地址:https://www.cnblogs.com/nuoforever/p/13996820.html
Copyright © 2011-2022 走看看