多文件编程

多文件编程

代码模块化

当需求比较复杂的时候或者做一个比较大的项目的时候,不可能将所有的源码都写到一个文件中,此时就需要进行模块化处理,思路如下:

  1. 将需求拆分成若干个小模块,每个模块对应一个源文件
  2. 给每个源文件提供一个头文件,通过这种方式实现函数的复用
    • 头文件进行函数声明
    • 源文件进行函数定义

假设我现在要做一个计算器,根据需求拆分成了加、减、乘、除四个模块,那么此时对应的源文件就是五个:

  • 处理加法的源文件:add.c
  • 处理减法的源文件:subtract.c
  • 处理乘法的源文件:multiply.c
  • 处理除法的源文件:divide.c
  • 主函数main(入口函数)对应的源文件:test.c

add.h

// add.h
#ifndef ADD_H_
// 函数声明
int add(int a, int b);
#define ADD_H_
#endif

add.c

#include "add.h"
#include <stdio.h>
int add(int a, int b)
{
    return a + b;
}

subtract.h

// subtract.h
#ifndef SUBTRACT_H_
// 函数声明
int sub(int a, int b);
#define SUBTRACT_H_
#endif

subtract.c

#include "subtract.h"
#include <stdio.h>
int sub(int a, int b)
{
    return a - b;
}

main.c

#include "substract.h"
#include "add.h"
#include <stdio.h>

int main()
{
    int number = 9;
    int number1 = 3;
    int res1 = add(number, number1);
    int res2 = sub(number, number1);
    printf("res1 = %d, res2 = %d\n", res1, res2);
    return 0;
}

关于乘法和除法的例子在这里就不写了,如法炮制就可以,完全是一样的。对于上面的代码有一下细节需要说明一下:

  • 一个头文件可能被多个源文件包含,只要包含了这个头文件,在源文件中就可以使用头文件中声明的函数了
  • 一个头文件中也可以包含其它头文件
  • 在包含多个头文件的时候,对顺序没有要求
  • 要避免自定义头文件被重复包含

在C语言中,一个源文件对应一个头文件并不是必须的,有时候多个源文件可以对应同一个头文件,也就是说N个源文件中定义的函数的声明都被放到了同一个头文件中。

calc.h

// add.h
#ifndef ADD_H_
// 函数声明
int add(int a, int b);
int sub(int a, int b);
#define ADD_H_
#endif

add.c

#include "add.h"
#include <stdio.h>
int add(int a, int b)
{
    return a + b;
}

subtract.c

#include "subtract.h"
#include <stdio.h>
int sub(int a, int b)
{
    return a - b;
}

main.c

#include "calc.h"
#include <stdio.h>

int main()
{
    int number = 9;
    int number1 = 3;
    int res1 = add(number, number1);
    int res2 = sub(number, number1);
    printf("res1 = %d, res2 = %d\n", res1, res2);
    return 0;
}

避免头文件重复包含

在包含头文件的时候可能由于失误将一个头文件包含了两次,或者是因为头文件的嵌套包含导致某个头文件被包含了多次(>1)

// a.h
#include "hello.h"
#include <stdio.h>
#include "hello.h"  // 头文件被重复包含

// b.h
#include "a.h"
    
// c.h 
#include "a.h"
#include "b.h"	// 头文件展开之后发现 a.h 在 c.h 中包含了两次

如果出现了以上情况,程序在编译的时候就会报错。为了避免同一个文件被include多次,C/C++中有两种方式:

  • 使用文件保护宏

    文件保护宏(header guard macro)是一种传统的预处理指令,用于防止头文件重复包含。文件保护宏可以确保在编译时只包含一次特定的头文件,从而避免由于多次包含导致的重复定义错误。

    文件保护宏需要在头文件的开头和结尾进行定义和结束,如下所示:

    #ifndef HEADER_FILE_NAME_H
    #define HEADER_FILE_NAME_H
    
    // 头文件的内容
    
    #endif // HEADER_FILE_NAME_H
    
    • HEADER_FILE_NAME_H 是一个唯一的标识符,用于确保宏定义的唯一性,因此每个头文件都应该使用不同的宏名称。
    • 可以根据需要自定义宏的名称,常见的做法是以头文件名称的大写形式作为宏的名称
    • 在编译过程中,首次包含头文件时,ifndef 条件为真,进入 #define 块,并定义了该宏。随后的重复包含,由于宏已经有定义,条件为假,不再执行 #define 块内的代码。
  • 使用 #pragma once

    #pragma once 是一种预处理指令,用于确保头文件只被编译一次。它是一种用于防止头文件重复包含的非标准的预处理指令,被大多数主流编译器所支持。

    使用 #pragma once 可以替代传统的头文件保护宏,如 #ifndef#define#endif。通过使用 #pragma once,可以更简洁地确保头文件只被编译一次,而无需手动编写宏定义。

    示例使用 #pragma once 的头文件:

    #pragma once
    
    // 头文件内容
    

    需要注意的是,虽然 #pragma once 在大多数情况下提供了简洁的头文件包含机制,而且几乎所有主流的编译器都支持它,但它不是C或C++的标准预处理指令。因此,如果您希望代码更具可移植性,可以继续使用传统的头文件保护宏。

posted @ 2023-09-08 16:00  ihuahua1415  阅读(57)  评论(0)    收藏  举报
*/