假设我有一个父目录A,有两个子目录B和C.
子目录C有一个helper.c和helper.h,如下所示:
//helper.c
void print(){
printf("Hello, World!\n");
}
//helper.h
void print();
现在,在子目录B中,我有一个main.c,它只调用print函数:
//main.c
#include<stdio.h>
#include"../C/helper.h"
void main(){
print();
}
我尝试了以下命令来编译main.c:
Command 1: gcc main.c //Gives undefined reference to 'print' error
Command 2: gcc main.c ../C/helper.c //Compiles successfully
现在我从main .c中删除了#include“../ C / helper.h”并再次尝试了Command 2.它仍然有效.
所以我有以下问题:
i)是否包含helper.h文件有什么区别
helper.c?
ii)为什么命令1失败?
iii)有没有办法编译我的C程序而无需指定
helper.c每次?
最佳答案 首先,您需要了解#include只是将#include参数中的任何文本添加到语句所在文件中的位置,例如:
//file1.h
void foo();
//main.c
#include "file1.txt"
int main(int argc, char **argv)
{
foo();
return 0;
}
将导致预编译生成此统一文件以进行编译:
//main.c.tmp
void foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
所以回答你的第一个和第二个问题:
如果包含只包含没有定义的声明(即函数签名)的头文件(或任何文件)(即函数实现),如上例所示,链接器将无法找到定义,您将获得’未定义的引用’错误.
当您包含包含定义的c代码文件(或任何文件)时,这些定义将合并到您的代码中,链接器将具有它们,这就是它工作的原因.
至于你的第三个问题
将c文件直接包含在其他c文件中是不好的做法,常见的方法是保留单独的c文件,其中包含暴露其提供的功能的标头,包括头文件和链接到已编译的c文件,例如在您的情况下:
gcc main.c helper.c -o out
将允许你在main.c中包含helper.c并且仍然有效,因为你指示编译器编译两个文件而不仅仅是main.c所以当链接发生时,将找到编译中的定义,你将不会得到未定义的行为错误
简而言之,这就是.我抽象了许多正在传递的概念. this是一篇很好的文章,详细描述了编译过程,this是对整个过程的一个很好的概述.