在C中分离接口和实现

时间:2014-06-21 08:58:47

标签: 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");
}

4 个答案:

答案 0 :(得分:3)

以下是一些原则:

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

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

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

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

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

  4. 因此,除了第3点之外,谨慎的做法是仅包含绝对需要的标头,并且仅包含实际需要它的文件。就个人而言,我经常只在之后包含一个标题我收到编译错误,告诉我有些东西丢失了。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

我的设置只会有两处变化。我会在头文件中包含所有标头,但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");
}

答案 3 :(得分:1)

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

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

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