.c文件和.h文件的关系

Chase620 等级 1045 0 0
标签: 变量C/C++

最近在做一个稍微有些复杂的项目。涉及到的函数、结构体、变量等比较多。通常,我编写c/c++项目的方式是,有一个main.c文件,该文件的main函数作为接口,调用其他函数。所有其他函数按功能,分别放在不同的.h文件中,这样的方式在编译和运行上肯定是没有什么问题的。

随着项目编写的深入,结构、逻辑以及变量的日趋复杂,总感觉上述方式的实现仍然不够清晰并且会导致一些冗余。忽然记起,在课堂上,老师提到过,.h文件一般用来存放函数声明和变量名,那么为什么我在.h文件中实现函数不会有问题呢?其他.c文件和main.c文件又有什么关系呢?这些,都使我不得不重新思考.h文件和.c文件的作用和关系。

要理清.h文件的作用,我们不妨看看.h文件的由来:

 “在编译器只认识.c(.cpp))文件,而不知道.h是何物的年代,那时的人们写了很多的.c(.cpp)文件,渐渐地,人们发现在很多.c(.cpp)文件中的声明语句就是相同的,但他们却不得不一个字一个字地重复地将这些内容敲入每个.c(.cpp)文件。但更为恐怖的是,当其中一个声明有变更时,就需要检查所有的.c(.cpp)文件。
    于是人们将重复的部分提取出来,放在一个新文件里,然后在需要的.c(.cpp)文件中敲入#include XXXX这样的语句。这样即使某个声明发生了变更,也再不需要到处寻找与修改了。因为这个新文件,经常被放在.c(.cpp)文件的头部,所以就给它起名叫做“头文件”,扩展名是.h。
    在我们语言的初学阶段,往往我们的程序只有一个.c的文件或这很少的几个,这时我们就很少遇到头文件组织这个头疼的问题,随着我们程序的增加,代码 量到了几千行甚至几万行,文件数也越来越多。这时这些文件的组织就成了一个问题,其实说白了这些文件的组织问题从理论上来说是软件工程中的模块设计等等的问题。”(引自c语言项目中.h文件和.c文件的关系

由上可以看出,.h文件最初就是用来给变量和函数提供一些全局性的声明,这些声明被其他.c文件共享,方便变量和声明的修改,使得大型代码逻辑更清晰更易于维护。因此.h文件中一般是声明,很少有代码的具体实现。

那么为什么在.h文件中实现函数也不会出错呢?在.h文件中实现函数与在.c文件中实现函数有什么区别和联系呢?普通的.C文件和包含main函数的c文件有什么区别和联系呢?

要解决上述问题,首先必须弄清编译器的工作原理。编译器的最终目的是将程序员编写的源代码转换成机器能够识别运行的二进制机器码。大体上分,可以分为4个步骤:

1.头文件的预编译,预处理

  编译器在编译源代码时,会先编译头文件,保证每个头文件只被编译一次。

  在预处理阶段,编译器将c文件中引用的头文件中的内容全部写到c文件中。

2.词法和语法分析(查错)

3.编译(汇编代码,.obj文件)

   转化为汇编码,这种文件称为目标文件。后缀为.obj。

4.链接(二进制机器码,.exe文件)

  将汇编代码转换为机器码,生成可执行文件。

更详细具体的流程可参考编译器的工作过程

在编译过程中,.h文件中的所有内容会被写到包含它的.c文件中,而所有的.c文件以一个共同的main函数作为可执行程序的入口。

因此,在.h文件中编写函数实现并不会出错,相当于所有.h的内容最后都被写到了main.c文件中。

但是为了逻辑性、易于维护性以及一些其他目的(可参考c语言中.h文件和.c文件的解析 ),一般在.h文件中写函数的声明,在.c文件中编写函数的实现。

收藏
评论区

相关推荐

linux基础命令1
language date date %Y/%m/%d date %H:%M:%S cal cal 2021 cal 01 cal 01 2021 cal 1 2021 bc scale3 quit tab tab tab ctrl c ctrl d shift pageUp shift p
.c文件和.h文件的关系
最近在做一个稍微有些复杂的项目。涉及到的函数、结构体、变量等比较多。通常,我编写c/c项目的方式是,有一个main.c文件,该文件的main函数作为接口,调用其他函数。所有其他函数按功能,分别放在不同的.h文件中,这样的方式在编译和运行上肯定是没有什么
C语言编译器为什么能够用C语言编写?
不知道大家有没有想过一个问题:C语言编译器为什么能够用C语言编写? 所谓C语言编译器,就是把编程得到的文件,比如.c,.h的文件,进行读取,并对内容进行分析,按照C语言的规则,将其转换成cpu可以执行的二进制文件。 在学习C/C++或者想要学习C/C++可以加入我们的学习交流QQ群: 954607083 ,领取学习资料 其本质在于对文件的读入,分析,及
asp.net调用Lodop实现页面打印或局部打印,可进行打印设置或预览
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="WebPrint.aspx.cs" Inherits="WebPrint" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/
IOS 面试题(四)
1. Object-C有多继承吗?没有的话用什么代替?
 ---------------------------- 1> OC是单继承,没有多继承 2> 有时可以用分类和协议来代替多继承 2. Object-C有私有方法吗?私有变量呢?
 ------------------------- 1> OC没有类似[@private](http://my.
JNI使用方式
作用:使Java能够同C/C++动态库(dll)进行交互。 编写过程:     1、native接口类,其中方法用native修饰,没有方法体。     2、通过javah命令编译native接口类,会生成.h的头文件。     3、用C编写一个dll文件         (1)需要引入刚生成的.h头文件         (2)实现头文件
Vala 多用途库制作
库可以通过JavaScript, Python, Lua, Ruby 中的gi模块调用 valac 编译时先生成对应的C文件然后再交给gcc编译 所生成的共享库与C编译生成库一致(C convention function call) 库制作过程中涉及主要文件类型: .so 共享库 .h   共享库描述文件(C convention) .
mysql导入导出
导出 1.将数据库mydb导出到e:\\mysql\\mydb.sql文件中: 打开开始->运行->输入cmd 进入命令行模式 c:\\>mysqldump -h localhost -u root -p mydb >e:\\mysql\\mydb.sql 然后输入密码,等待一会导出就成功了,可以到目标文件中检查是否成功。 2.将数据库my
C++ 、java 和 C# 的区别
### 一、基础类型 **c++:** ![file](https://oscimg.oschina.net/oscnet/up-a9755823aa67cde64008292ce91c06adb33.png) \*\* java:\*\* ![file](https://oscimg.oschina.net/oscnet/up-983f3b117d6f
Cocos Creator 动态设置Canvas的宽度与高度,更改适配
let c = this.node.getComponent(cc.Canvas); c.fitHeight = true; c.fitWidth = false; let h = 960 \* cc.winSize.height / cc.winSize.width; c.designResolution = new cc.Size(960,
Linux音视频开发之一:用V4L2采集webcam摄像头数据mjpeg 和yuv
网上v4l2介绍的文章文多,api的使用我就不再说了,只在这里贴出我的C++封装类。 源码直达:[https://gitee.com/noevilme/libwebcam](https://gitee.com/noevilme/libwebcam) webcam\_v4l2.h /** * Copyright(C)2020 Noevi
Python code question 6
### Question 6 Level 2 Question: Write a program that calculates and prints the value according to the given formula: Q = Square root of \[(2 \* C \* D)/H\] Following are the fix
Redis redis
redis-benchmark benchmark]# redis-benchmark -h 127.0.0.1 -p 6382 -c 500 -n 200000  -n Total number of requests (default 100000) \-c 500个并发连接, 其他参数请通过  redis-benchmark -
Shell脚本之sed的使用
1.sed命令;主要作用是查找;新增 删除 和修改替换。 user.txt  daokr#cat user.txt ID Name Sex Age 1 zhang M 19 2 wang G 20 3 cheng M 10 4 h
springboot项目启动,停止,重启
参考博客 https://www.cnblogs.com/c-h-y/p/10460061.html 打包插件,可以指定启动类 <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifact