关于C编程中的.c文件和.h文件?

时间:2017-04-19 08:13:24

标签: c

f中有一个foo.c函数,我将f Prototypes放入头文件

然后,有3个问题:

  1. 标题文件必须命名为foo.h吗?
  2. foo.cfoo.h必须位于同一目录吗?
  3. 如果两个问题的答案都是,也就是说,标题文件可以命名为f.hfoo.cf.h可以是不同的目录。看一个例子:
  4. 〜/的CFile / foo.c的

    #include "~/hfile/f.h"
    int f(void){
         ...
    }
    

    〜/ HFILE / f.h

    int f(void);
    

    〜/主/ cmain.c

    #include "~/hfile/f.h"
    int main(void){
        f(); 
        ...  
    }
    

    然后,当我在 cmain.c 中调用f函数时, cmain.c 可以通过{{1}找到 fh 指令,但 cmain.c 如何通过 fh 查找 foo.c ,因为 cmain.c 仅包括 fh 不包括 foo.c ?或者编译器或链接器如何通过 f.h 找到 foo.c

7 个答案:

答案 0 :(得分:6)

  

头文件必须命名为foo.h吗?

不,但使用将程序的相关部分联系在一起的名称(即使它是结构性联系,而不是逻辑联系)是一件非常合理的事情。请记住,代码/源代码树适用于人类,而不是机器。

  

foo.c和foo.h必须在同一目录中

没有。但必须正确设置包含路径,以便构建foo.c

  

但编译器或链接器如何找到foo.c并从foo.c调用f?

您必须为编译器/链接器指定这些内容。查阅他们的文档。由于为大型项目执行此操作可能有点令人生畏,因此甚至可以根据您指定的规则为您管理构建。一个典型的例子是make程序。

至于您添加的代码示例。简单地包含标题并不足以构建程序。标头仅包含声明。您必须指示链接器获取相关的目标文件并将它们链接到单个可执行文件中。

想想是否作为拼图游戏。每个声明都在一个具有特定形状的目标文件中。每个函数定义都是具有特定形状的目标文件中的碰撞。连接器的工作就像将拼图放在一起时那样适应凹痕。

答案 1 :(得分:3)

<强> 1。头文件必须命名为foo.h吗?

这不是必要的,但它可以很方便,而且大部分时间都是不成文的规则。

<强> 2。 foo.c和foo.h必须在同一个目录中吗?

这不是必需的。您可以给c编译器包含目录。或者您可以包含相对于目录的内容,例如

#include "inc/foo.h"

第3。如果两个问题的答案都是否定的,也就是说,头文件可以命名为f.h,foo.c和f.h可以在不同的目录中。然后,当我调用f函数时,它可以通过#include指令找到f.h文件,但编译器或链接器如何找到foo.c并从foo.c调用f?

请参阅答案2.例如,请参阅带有-I选项(https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html

的gcc手册

更新: 由于问题已经延长,也许您还可以查看较早的帖子C/C++ header and implementation files: How do they work?

答案 2 :(得分:2)

  1. 不,你可以随意命名头文件
  2. 不,你可以把头文件放在任何你喜欢的地方
  3. 如果头文件未与源文件放在同一位置,则必须将头文件的位置移交给编译器。如何为gcc执行此操作在此问题的答案中进行了描述:How to include header files in GCC search path?

答案 3 :(得分:2)

您可以根据需要为文件命名。您可以将文件放在几乎任何您喜欢的位置,只要您正确告诉编译器和链接器这些文件的位置即可。你甚至不必让文件名以.c.h结尾 - 这些大多只是惯例,但是好的。 我真的建议您使用.c.h文件名结尾!

假设您调用一个文件foo.c并将其放在~/my-sources目录中。另外说你调用另一个文件bar.header并将其放在~/my-headers目录中。然后你的#include指令必须看起来像这样:

#include "../my-headers/bar.header"

这假设您使用的是类UNIX系统。您必须应用您对所使用的操作系统的了解才能使#include指令正常工作。

因为编译时源文件中的头文件是包含,所以实际上几乎就像源文件中的头文件一样具有整个内容。因此,只要您告诉编译器在哪里找到您的文件(在编译时通过命令行,并在#include指令中使用正确的路径),您就可以将文件放在任何位置。

答案 4 :(得分:2)

  1. 没有
  2. 没有
  3. 当您想要编译输出(可以是进程或静态/动态库)时,您可以为编译器提供源文件(在您的情况下为foo.c),然后它将搜索所有这些源文件以查找功能的定义。

答案 5 :(得分:2)

  
      
  1. 头文件必须命名为foo.h吗?
  2.   

  
      
  1. foo.c和foo.h必须在同一个目录中吗?
  2.   

  
      
  1. 如果两个问题的答案都是否定的,那就是一个头文件   可以命名为f.h,foo.c和f.h可以在不同的目录中。然后,什么时候   我调用f函数,它可以通过#include指令找到f.h文件,但是如何   编译器或链接器找到foo.c并从foo.c调用f?
  2.   

这取决于你。如果您将标题f.h和源文件foo.c放在相同目录中,则只需将标题文件添加到foo.c文件中,例如:

#include "f.h"

但是,如果您将标题f.h和源文件foo.c放在其他目录中,则将标题文件的路径添加到foo.c中,如:

#include "Your_header_file_Path/f.h"

答案 6 :(得分:1)

#include literally inserts所使用的引用文件。

如果您想知道最终给编译器的内容,请查看preprocessor中间件。

链接器的工作方式不同,它只包含所有对象的列表。如果对象在那里,它可以找到它 如果您没有正确引用它,它会以某种implicit declaration警告您。