头文件、源文件 及extern的使用

2023-05-16

头文件与源文件的作用

1. 编译器的工作过程

简单的说其实要理解C文件与头文件(即.h)有什么不同之处,首先需要弄明白编译器的工作过程,一般说来编译器会做以下几个过程:

1.预处理阶段
2.词法与语法分析阶段
3.编译阶段,首先编译成纯汇编语句,再将之汇编成跟CPU相关的二进制码,生成各个目标文件 (.obj文件)
4.连接阶段将各个目标文件中的各段代码进行绝对地址定位,生成跟特定平台相关的可执行文件,当然,最后还可以用objcopy生成纯二进制码,也就是去掉了文件格式信息。(生成.exe文件)

编译器在编译时是以C文件为单位进行的,也就是说如果你的项目中一个C文件都没有,那么你的项目将无法编译,连接器是以目标文件为单位,它将一个或多个目标文件进行函数与变量的重定位,生成最终的可执行文件,在PC上的程序开发,一般都有一个main函数,这是各个编译器的约定,当然,你如果自己写连接器脚本的话,可以不用main函数作为程序入口!!!!
(main .c文件 目标文件 可执行文件 )

2. 头文件与源文件的解析

1 . (.h)叫做头文件,它是不能被编译的。

“#include”叫做编译预处理指令,可以简单理解成,在1.cpp中的#include”1.h”指令把1.h中的代码在编译前添加到了1.cpp的头部。每个.cpp文件会被编译,生成一个.obj文件,然后所有的.obj文件链接起来你的可执行程序就算生成了。

发现了没有,你要在.h文件中严格区分声明语句和定义语句。好的习惯是,头文件中应只处理常量、变量、函数以及类等等等等的声明,变量的定义和函数的实现等等等等都应该在源文件.cpp中进行。

至于.h和.cpp具有同样的主文件名的情况呢,对编译器来讲是没有什么意义的,编译器不会去匹配二者的主文件名,相反它很傻,只认#include等语句。但是这样写是一种约定俗成的编程风格,一个类的名字作为其头文件和源文件的主文件名比如Class1.h和Class1.cpp,这个类的声明在Class1.h中,实现在Class1.cpp中,我们人类看起来比较整齐,读起来方便,也很有利于模块化和源代码的重用。

为什么这个风格会约定俗成?有一句著名的话,叫“程序是为程序员写的”。

2.h文件和cpp文件也就是说,

在h文件中声明Declare,而在cpp文件中定义Define。

“声明”向计算机介绍名字,它说,“这个名字是什么意思”。而“定义”为这个名字分配存储空间。无论涉及到变量时还是函数时含义都一样。无论在哪种情况下,编译器都在“定义”处分配存储空间。

对于变量,编译器确定这个变量占多少存储单元,并在内存中产生存放它们的空间。
对于函数,编译器产生代码,并为之分配存储空间。函数的存储空间中有一个由使用不带参数表或带地址操作符的函数名产生的指针。

定义也可以是声明。如果该编译器还没有看到过名字A,程序员定义int A,则编译器马上为这个名字分配存储地址。声明常常使用于extern关键字。如果我们只是声明变量而不是定义它,则要求使用extern。对于函数声明, extern是可选的,不带函数体的函数名连同参数表或返回值,自动地作为一个声明。

extern 关键字的使用

1. 主函数源文件中不包含头文件

test1.cpp 文件
int test = 10000;

void  test_fun(int& temp)
{
    temp += 1111;
}
主函数 yuan.cpp 文件
#include<iostream>
using namespace std;

extern int test;
extern void  test_fun(int& temp);

int main()
{
    cout << test << endl;
    test_fun(test);
    cout << test << endl;
    return 0;
}

总结:编写单独的 .cpp 文件来实现 函数 或者 变量 ,在主函数使用前需要声明变量为外部变量。不然编译可以通过,但是在目标文件链接的时候就会出错。

2. 主函数源文件中包含头文件

test.h 文件
#pragma once
#include<iostream>

using namespace std;

extern int intext; //外部变量
void test_function();
extern void function();//外部函数
test.cpp 文件
#include"test.h"

int intext = 10;

void test_function()
{
    cout << "test" << endl;
}
function.cpp 文件 (这个实现外部的函数)
#include<iostream>

void function()
{
    std::cout << "extern-function" << std::endl;
}
yuan.cpp 文件 (主函数)
#include"test.h"

int main()
{
    cout << intext << endl;
    test_function();
    function();
    return 0;
}

总结:可以通过建立一个.h文件来说明一些外部的变量和函数。这样通过引用头文件就可以实现真确的编译及链接。
参考:
https://www.cnblogs.com/with-a-orchid/p/4262951.html
https://www.cnblogs.com/fenghuan/p/4794514.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

头文件、源文件 及extern的使用 的相关文章

随机推荐

  • STM32F103mini教程学习总结与心得(一)

    关注同名微信公众号 混沌无形 xff0c 阅读更多有趣好文 xff01 1 引脚是否兼容5V的判断 xff1a 引脚表中PF表示5V xff0c 原理图中有ADC的引脚为3 3V 2 PT xff1a 容忍5V xff0c 没有PT标示 x
  • STM32F103mini教程学习总结与心得(二)---->串口通信

    关注同名微信公众号 混沌无形 xff0c 阅读更多有趣好文 xff01 一 串口原理 1 处理器与外部设备通信的两种方式 xff1a 并行通信 xff08 速度快 xff0c 占用资源多 xff09 43 串行通信 xff08 反之 xff
  • 电源管理与驱动设计笔记

    关注同名微信公众号 混沌无形 xff0c 阅读更多有趣好文 xff01 1 电源管理的功能 xff1a 具备电压过高保护 电流过大保护 电量监测 过放保护 等功能 gt 自主充电 2 一款清洁机器人的运动控制系统方案设计示意图 2 1电源充
  • (4)(4.3) 将固件加载到已有ArduPilot固件的主板上

    文章目录 前言 1 将自动驾驶仪连接到电脑 2 选择COM端口 3 安装固件 4 使用测试版和开发版 4 1 测试版 4 2 最新开发版本 4 3 自定义固件构建服务器 5 测试 前言 这些说明将告诉你如何将最新的固件下载到已经安装了 Ar
  • 【MDK KEIL】keil添加文件夹目录结构(批量添加.c和.h文件到工程中)(keil添加头文件路径)

    第一步打开创建文件夹选项 xff1a 第二步 xff1a 直接创建删除 或者上移下移 就好了 3 添加文件夹的同时别忘记导入头文件 xff1a
  • 单片机IO详解(上拉 下拉 准双向 输入 输出 推挽 开漏)

    目录 上拉 xff1a 下拉 输入 xff1a 上拉输入 下拉输入 输入浮空 模拟 施密特输入 xff1a 三态输入 xff1a 输出 复用推挽和推挽输出区别 推挽输出特点 开漏输出 xff1a 准双向口 一般单片机都会提供上拉和下拉功能
  • 局部路径规划算法——实现DWA(dynamic window approach)控制空间采样

    DWA算法是局部路径规划算法 xff0c 在全局路径规划算法完成后 xff0c DWA算法能够根据当前小车 xff08 机器人 xff09 位置 障碍物 终点的位置进行控制空间 xff08 速度 角速度 xff09 的采用 xff0c 从而
  • make和cmake简要介绍

    GCC GCC xff08 GNU Compiler Collection xff0c GNU编译器套件 xff09 是由GNU开发的编程语言译器 GNU编译器套件包括C C 43 43 Objective C Fortran Java A
  • 什么是小端模式,什么是大端模式

    字节序 前言 内存在读写数据的时候 xff0c 都是以字节为单位进行读写的 xff0c 其最小的读写单位也是字节 一个字节占8位 xff0c 如果暂且只考虑无符号数 xff0c 那么其能表示的范围只有0 255这256个整数数值 如果将一个
  • 多旋翼飞行器螺旋桨动力学模型

    1 多旋翼螺旋桨动力学模型 1 1 螺旋桨几何位置基本描述1 2 螺旋桨拉力及拉力力矩1 3 螺旋桨反扭力矩1 4 螺旋桨陀螺力矩1 5 螺旋桨动力学方程 1 多旋翼螺旋桨动力学模型 1 1 螺旋桨几何位置基本描述 坐标系分为多旋翼机体重心
  • 雷达天线孔径与分辨率

    我们现在讲一下真实孔径的问题 xff0c 我们先有一个 最小分辨角 的概念 xff0c 根据瑞丽 xff08 Rayleigh xff09 判据 xff0c 几何光学 xff0c 物体上的一个发光点经透镜成像后得到的应是一个几何像点 而由于
  • 【新手】关于ros包安装时,提示找不到相应的ros包(unable to locate package ros- **** )

    我是在学习这个大佬的教程 xff1a 从零开始的ROS学习之仿真 43 SLAM https blog csdn net u011612364 article details 122147741 xff08 引用 xff09 时发现我自己出
  • c++实现守护进程

    概述 Linux Daemon xff08 守护进程 xff09 是运行在后台的一种特殊进程 它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件 约束 守护进程一般在系统启动时开始运行 xff0c 除非强行终止 xff0c 否
  • linux C++ 环境下的ActiveMQ学习

    ActiveMQ 1 概述 ActiveMQ 是Apache出品 xff0c 最流行的 功能强大的即时通讯和集成模式的开源服务器 ActiveMQ 是一个完全支持JMS1 1和J2EE 1 4规范的 JMS Provider实现 提供客户端
  • Django与mysql建立长连接

    问题 xff1a 每次请求操作mysql数据库都会从新创建一个connect实例 xff0c 大大降低了数据处理的效率 还是django不够熟悉 解决办法 xff1a 自Django1 6版本后 xff0c 官方提供支持长连接 xff0c
  • Python ActiveMQ 消费者实现

    encoding utf 8 import stomp import sys import thread Create your tests here topic name 61 39 topic your topic name 39 br
  • Django 服务启动2次问题

    首先 xff0c 我们的操作如下 xff1a 一 命令行的启动服务 xff1a python manage py runserver 0 0 0 0 8000 二 服务启动行为 try os environ setdefault 34 DJ
  • Django settings.py配置总结

    1 版本 xff1a 1 8 9 2 解决数据库时间和当前系统时间不一致问题 设置USE TZ 61 False 3 时区配置 xff1a TIME ZONE 61 39 Asia Shanghai 39 4 静态文件js css等的引用路
  • Extern关键字在vscode中不生效的解决办法

    今天回顾extern关键字的时候遇到一个问题 a c里的代码 b c里的代码 这么简单的几个代码 vscode竟然给我报错 为什么 抱着这个问题去逛了下csdn 终于让我找到了问题所在 原来vscode默认只能对单文件编译 即使俩文件在同一
  • 头文件、源文件 及extern的使用

    头文件与源文件的作用 1 编译器的工作过程 简单的说其实要理解C文件与头文件 xff08 即 h xff09 有什么不同之处 xff0c 首先需要弄明白编译器的工作过程 xff0c 一般说来编译器会做以下几个过程 xff1a 1 预处理阶段