多文件编程

2023-11-16

什么是多文件编程

多文件编程,指的是把不同功能的函数封装到不同的文件中的编程方式,其中.c文件内装有函数本体,.h文件内放入函数声明,以供其他函数调用。多文件编程也被称为模块化编程,其中一个.c文件和一个.h文件被称为一个模块。

我们初学c语言函数调用时,习惯将功能函数放在主函数下方,在主函数上面进行函数声明。对于小规模的编程来说这样确实可以,但对于大规模的C语言项目来说,包含很多个函数,写在一个文件中不利于查找、组织、识别。于是就诞生了多文件编程。

人为的将复杂项目中的很多函数分成了不同的功能模块,分开放在不同的.c文件中,并用不同的.h文件进行声明,这就是多文件编程。
在这里插入图片描述
 
 

< > 与 " "

对于库函数,我们习惯用#include <xxx.h>进行声明,如#include <stdio.h>。而在多文件编程中,我们用#include "xxx.h"进行声明,如#include “function1.h”。这两种声明方式有什么区别呢?

#include <stdio.h>

代表编译时直接在软件设置的指定路径中寻找里面是否有stdio.h的库文件。如果有,直接加载;如果没有,报错(无法找到库文件)。

#include “function1.h

代表编译时先寻找你正在编辑的源代码文件所在的文件夹里面有没有function1.h的库文件。如果有,优先加载这个文件(指定路径下如果也有function1.h,它就被无视了),如果没有,才会在指定路径中寻找是否有function1.h的库文件。如果有,直接加载;如果没有,报错(无法找到库文件)。
 
 

多文件编程方法

例如,当需要开发包含两个功能函数(function1和function2)的C程序时,传统的做法是在main.c中分别编写main函数、function1函数和function2函数,在main函数之前声明两个功能函数,并调用。

而如果用多文件编程,则过程如下:

  1. 创建两个.c文件,function1.c和function2.c
  2. 分别在两个.c文件内定义需要的函数
  3. 创建两个.h文件,文件名与两个.c文件一致,即function1.h和function2.h
  4. 在两个.h文件中分别包含各自所需的库文件,声明在.c中定义的函数
  5. 在main.c文件中包含两个.h文件,在main函数中直接调用两个自定义函数

又例如,当开发更加复杂的项目(如学生管理系统)时,我们可以将库函数调用、宏定义、结构体定义、全局变量定义等整个项目都需要使用的内容放在一个头文件中,在需要使用的文件内包含该文件。

在这个头文件中,就包含了若干库函数和结构体定义,除了代码的头两行。那么代码的头两行是干什么的呢?
 
 

变量重复定义与头文件重复包含

 

·变量重复定义

若在不同功能函数中都定义了相同内容(如结构体),则会出现变量重复定义。

a.h:
struct stu {
	char name[10];
	int grade;
}
 
b.h:
#include "a.h"
 
c.h:
#include "a.h"
 
main.c:
#include "b.h"
#include "c.h"

该代码中结构体stu在main中进行了两次定义,出现了变量重复定义。
 

·头文件重复包含

在不同头文件中包含了相同头文件,这种情况就叫做头文件重复包含。

a.h:
int fun();
 
b.h:
#include "a.h"
 
c.h:
#include "a.h"
 
main.c:
#include "b.h"
#include "c.h"

该代码中main函数内定义了两次fun() ,出现了头文件重复包含。
 

·为什么要避免重复包含?

  1. 在编译c程序时候,编译器会将你源程序中#include的头文件完整的展开,如果你在同一个.c下多次包含相同的头文件,会导致编译器在后面的编译步骤多次编译该头文件,使整个项目编译速度变的缓慢,后期的维护修改变得困难。
  2. 头文件重复包含可能会使程序在编译链接的时候因变量重复定义而崩溃。
     

·如何解决

1. #ifndef

//条件编译
//test.h
#ifndef _TEST_H_
#define _TEST_H_                //一般是文件名的大写
//文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,
//………………………………
//………………………………
//………………………………
#endif

优点

  1. 不光可以保证同一个文件不被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不被同时包含
  2. 受C/C++语言标准的支持,不受编译器的任何限制

缺点

  1. 如果不同头文件中的宏名不小心“撞车”,可能就会导致你看到头文件明明存在,编译器却硬说找不到声明的状况
  2. 由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,ifndef会使得编译时间相对较长,因此一些编译器逐渐开始支持#pragma once的方式

2. #pragma once

//#pragma once
//test.h
#pragma once
//………………………………
//………………………………
//………………………………

优点

  1. 你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题
  2. 大型项目的编译速度也因此提高了一些

缺点

  1. 就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含
  2. 而#pragma once方式却不受一些较老版本的编译器支持,一些支持了的编译器又打算去掉它,所以它的兼容性可能不够好
     

·小总结

对于变量重复定义的问题,头文件尽量只有声明,不要有定义!
对于头文件重复包含的问题,根据实际情况使用#ifndef#pragma once

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

多文件编程 的相关文章

随机推荐

  • react学习—属性默认值和类型验证

    属性默认值和类型验证 一 属性默认值 1 函数组件属性默认值 2 类组件默认属性值 二 属性类型验证 1 常见值类型 2 是否必传isRequired 3 其它类型验证 4 自定义验证 一 属性默认值 通过一个静态属性defaultProp
  • 基础算法matlab

    常用算法 knn knn clc close all clear training mvnrnd 2 2 eye 2 50 mvnrnd 2 2 2 eye 2 50 mvnrnd 2 2 2 eye 2 50 group ones 50
  • Comparable和Comparator的区别以及Lambda表达式实现

    Comparable和Comparator的区别 1 comparable里面的ComparaTo 是TreeSet和TreeMap里面add 与put 方法里面调用对象的ComparaTo 通过返回值 来确定它 是否存在or顺序 他是内置
  • 计算机二级证书免费发到学校,计算机二级证书去哪里领取

    随着计算机等级考试成为了当代大学生必考的考试之一 越来越多的同学都加入到考试大军 通过了计算机二级考试 证书如何领取呢 下面是小编整理的详细内容 一起来看看吧 计算机二级证书领取方法 1 一般情况下是考试结束后50个工作日左右出成绩及出证
  • echarts 中 symbol 自定义图片

    首先我使用的技术框架的VUE 当然该方法在其他框架也是适用的 这点大家注意一下 在官方文档里面 修改标记的图形 symbol 的方法有三种 一 ECharts 提供的标记类型有 circle rect roundRect triangle
  • .NET C#基础(5):结构体 - 高性能代码的基石

    0 文章目的 本文面向有一定 NET C 基础知识的学习者 介绍C 中结构体定义 使用以及特点 1 阅读基础 了解C 基本语法 了解 NET中的栈与托管堆 2 值类型 2 1 NET的两大类型 在 NET中 所有类型都是object类型的子
  • Excel行高、列宽怎么调整?

    在日常工作中 经常会需要用到Excel表格 如果打开的Excel表格行高列宽不是我们想要的 要怎么调节到合适的大小呢 方法一 打开Excel表格 按 Ctrl A 快捷键 选中全部表格 或者点击表格左上角 行号和列标交汇处的灰色小三角 也可
  • CEPH PG incomplete状态修复

    某运营商的Kubernetes项目物理机停机维护 重启后Kubernetes部分pod无法挂载PVC 请求超时 该Kubernetes集群的后端存储使用ceph rbd块存储 检查ceph集群状态异常 root ceph node01 ce
  • Nacos

    一 Nacos Spring Cloud Alibaba https spring io projects spring cloud alibaba Nacos 官网 https nacos io zh cn docs what is na
  • openGL library下载地址

    GLUT下载页面 http www opengl org resources libraries glut glut downloads php GLUT for Win32下载页面 http www xmission com nate g
  • linux系统虚拟机安装centos7

    一 安装 第一步 下载安装VMware Fusion Mac版本下载后双击安装 这里不做过程记录 第二步 下载CentOS 7安装包 CentOS 7 x86 64 DVD 1810 iso 本文不提供下载地址 第三步 在VMware Fu
  • Vue中使用render 封装el-table解决多级表头自定义模板

    vue中多数情况下使用template封装组件逻辑清晰结构简单 但是在某些情况下 比如非常简单的组件 vue render简单解析或者template无法解决某些场景下 使用完全javascirpt能力就显得尤为重要 文章目录 使用rend
  • VB.Net常用的正则表达式(实例)

    d 非负整数 正整数 0 0 9 1 9 0 9 正整数 d 0 非正整数 负整数 0 0 9 1 9 0 9 负整数 d 整数 d d 非负浮点数 正浮点数 0 0 9 0 9 1 9 0 9 0 9 1 9 0 9 0 9 0 9 1
  • 给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数---百度笔试题

    题目 给定一个存放整数的数组 重新排列数组使得数组左边为奇数 右边为偶数 要求 空间复杂度O 1 时间复杂度为O n 我自己写了一下 之前写的那个不对 现在重写了 时间复杂度达到O n void swap int a int i int j
  • python数据可视化-折线图

    可通过ab173 com查看json数据 导入json import json 处理数据 美国为例 f us open D 桌面 折线图数据 美国 txt r encoding UTF 8 us data f us read 美国的全部内容
  • VMware17虚拟机安装及Linux系统搭建(详细版)

    作者简介 大家好 我是小杨 个人主页 小杨 的csdn博客 希望大家多多支持 一起进步呀 前言 VMware是一个虚拟PC的软件 可以在现有的操作系统上虚拟出一个新的硬件环境 相当于模拟出一台新的PC 进行计算机的管理 软件安装 文件的使用
  • 这十个步骤让你的 App 避规ios 4.3被拒问题

    4 3 垃圾应用 请不要为同一个 App 创建多个套装 ID 如果您的 App 针对特定位置 运动队 大学等存在不同版本 请考虑提交单个 App 并提供 App 内购买以提供差异功能 同时 请避免继续在已有大量类似 App 的类别下进行开发
  • kubectl应用

    文章目录 kubectl用法概述 kubectl输出格式 kubectl操作示例 kubectl用法概述 kubectl命令语法 kubectl command TYPE NAME flags 其中 command TYPE NAME fl
  • 如何计算内存大小

    对电子产品 存储介质厂家来说 是按进率1000来计量的 即1000B 1KB 1000KB 1MB 1000MB 1GB 也就是为什么硬盘分区后 会造成缩水 比如80G硬盘实际等于76G 的原因 因为系统是按1024进率来进行分区的 注 我
  • 多文件编程

    文章目录 什么是多文件编程 lt gt 与 多文件编程方法 变量重复定义与头文件重复包含 变量重复定义 头文件重复包含 为什么要避免重复包含 如何解决 1 ifndef 2 pragma once 小总结 什么是多文件编程 多文件编程 指的