繁体   English   中英

在C中分离接口和实现

[英]Separating the Interface and Implementation in C

在将接口与C中的实现分开时,哪里是包含头文件的正确位置?

在接口文件(.h文件)或实现文件(.c文件)中? 为什么?

我的示例代码:

console.h

#ifndef CONSOLE_H
#define CONSOLE_H

#include <windows.h>

void gotoxy (const WORD x, const WORD y);

void clearScreen();

#endif

console.c中

#include <stdlib.h>
#include "console.h"

COORD coord = {0,0};

void gotoxy (const WORD x, const WORD y){
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void clearScreen(){
    system("cls");
}

以下是一些原则:

  1. 不必要的包含标头只会增加编译时间。
    这可能听起来很容易被忽视,而且一般来说,但如果你养成了包含太多的习惯,它就会成为一个问题。

    想象一下,您的项目有一个通用标题,包括所有其他项目标题以及它们可能需要的所有系统标题。 所以任何.c文件只需要包含这一个标题并完成它。 这很方便。 但是,除了延长每个.c文件的编译时,它还保证每次更改单个标头时都必须重新编译整个项目 这将显着减慢您的修改 - 编译 - 测试周期。

  2. 您必须避免创建循环包含依赖项。
    如果你确实创建了一个循环包含,那你就麻烦了。 因此,最好避免包含任何不必要的内容:包含的内容越少,触发循环包含的标头越少。 有时您可能需要插入前向声明而不是包含。

  3. .c文件必须包含其.h文件。
    如果你没有这样做,.c文件中的函数签名将不会根据.h文件中的声明进行检查,并且会出现疯狂。

    这个原则的问题是,如果.h文件没有定义实现所需的类型,那么你的.c文件可以在没有include的情况下正常编译。 然而,包含必须在那里以防止签名不匹配。

因此,除了第3点之外,谨慎的做法是仅包含绝对需要的标头,并且仅包含实际需要它的文件。 就个人而言, 我收到编译器错误告诉我缺少某些内容 ,我经常只包含一个标题。

Include指令应始终包含在需要它们的文件中,或者使您更容易阅读和理解代码。

在您的示例中,您在console.h中包含了windows.h. 对于这样一个常见的头文件,可以将它留在console.h中。 但是,如果您正在使用另一个您编写的库,并且尚未被广泛采用,那么将它包含在两个文件中是明智的,以防止将来的开发人员不得不搜索头文件来搜索提供功能的文件。在console.c中。

我的设置只有两个变化。 我会在头文件中包含所有头文件,除了包含头文件所必需的console.h头文件。 第二,当你#define CONSOLE_H 1 ,给它一个值1就可以了。 我只是阻止了一个未初始化的标签。 看起来不错。

console.h

#ifndef CONSOLE_H
#define CONSOLE_H  1

#include <windows.h>
#include <stdlib.h>

void gotoxy (const WORD x, const WORD y);

void clearScreen();

#endif

console.c中

#include "console.h"

COORD coord = {0,0};

void gotoxy (const WORD x, const WORD y){
    coord.X = x;
    coord.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void clearScreen(){
    system("cls");
}

就像在评论和其他答案中已经提到的那样 - 包括应该在需要它们的文件中。

但是,对于复杂/大型项目,我建议设计接口,使它们只需要处理程序/引用实际数据而不是实际数据。 这允许在头文件中使用前向声明,在实现文件中使用实际包含。 其原因是避免紧耦合 耦合通常会导致非常有问题的行为,强制包含不直接需要的标头(甚至创建循环依赖,导致编译失败并需要进行大量更改!),增加编译时间并损害此类软件属性作为模块化,可维护性和可扩展性。

也就是说,在大多数情况下(例如stdio.h,windows.h等)都需要常见的标题(通常是你正在使用的环境的一部分) - 包括这些标题虽然汇编,但不会损害软件质量时间可能还会增加。 解决此问题的一种方法是使用预编译头

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM