我的理解是C ++(和C,我猜)头文件从不编译,只是作为他们描述的C ++文件接口的解释。
因此,如果我的头文件描述了一个hello()函数,那么包含头的一些程序将知道hello()以及如何调用它以及提供它的参数等等。
然而,在编译之后(和链接之前,我猜?我不确定),当hello.c文件是二进制机器代码,而hello.h仍然是C ++时,编译器/链接器如何知道如何根据头文件中是否存在声明来调用二进制blob中的函数?
我理解符号表,抽象语法树等概念(例如,我过去使用过编译器类),但这是我所知的差距。)
答案 0 :(得分:0)
hello()的实现假定某个调用约定(堆栈中的参数,清除调用者或被调用者的堆栈等)。
编译器使用正确的调用约定生成代码。它可以使用头文件中的信息来执行此操作(例如,该函数在Windows程序中标记为__stdcall),或者它可以使用它的默认调用约定。编译器还将使用头文件来确保您使用正确数量和类型的参数调用例程。一旦编译器生成代码,就不再使用头文件。
链接器不关心调用约定它的主要职责是通过修复模块和它调用的任何库之间的引用来修补你编译的二进制文件。
答案 1 :(得分:0)
C / C ++编译单元(cpp文件/ c文件)包括所有头文件(作为文本)和代码。
头文件有助于解释如何生成调用指令
push arg1
push arg2
call _some_function
如果编译单元包含_some_function
,那么这将在编译时解决。
否则它将成为未定义的符号。如果是这样,当链接器出现时,它会查看所有目标文件和库以解析所有未定义的符号。
库文件是可选的。当链接器查找库文件时,只有在满足某个符号时才会添加它,否则它不会添加到二进制文件中。
对象文件(忽略优化)将完全添加到二进制文件中。
答案 2 :(得分:-1)
构建C ++程序分为两步:编译和链接。 标题用于编译您正在编写的模块。二进制文件用于链接:它包含在相应的头文件中定义的方法的编译代码。标题必须与已编译的内容相匹配。在链接时,您将了解您的标头是否具有与二进制文件中编译的方法签名相匹配的方法签名。