我正在尝试为一个简单的程序创建一个makefile,它依赖于一个简单的文件和一个存储在c文件中的函数。以下是文件:
function.c:
#include <stdio.h>
#include "function.c"
int main()
{
int a, b;
printf("Enter numbers a, and b: ");
scanf("%d %d", &a, &b);
printf("Here is ur answer: %d", random_fun(a, b));
return 0;
}
main.c中:
OBJS = main.o function.o
program: $(OBJS)
$(CC) -o $@ $?
clean:
rm $(OBJS) program
这是我的makefile:
duplicate symbol _random_fun in:
main.o
function.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see
invocation)
make: *** [program] Error 1"
每当我尝试输入make时,我都会收到以下错误:
play.filters.enabled=[youDesiredFilter]
不确定我做错了什么。我可以分别编译每个代码和主要工作。我正在为我正在处理的另一个项目得到同样的错误,所以我尝试了一个只涉及这两个C文件的非常简单的案例,我得到了同样的问题。我是一个相当新的makefile,什么不是,如果我犯了一个愚蠢的错误,请耐心等待。
答案 0 :(得分:1)
您应该阅读C中定义和声明之间的区别。
当您将function.c
包含在main.c
中时,您的函数random_func
会被定义两次。链接器无法决定使用哪一个,因此它会出错。
对于您的用例,您应在random_func
或其他标题文件中声明main.c
。
答案 1 :(得分:0)
预处理后文件会发生这种情况:
// function.c
int random_fun(int n, int m)
{ int g;
n = n+m;
m=n/3;
g=n*m;
return g;
}
-
// main.c
// contents of stdio.h goes first. I omit it for brevity
int random_fun(int n, int m)
{ int g;
n = n+m;
m=n/3;
g=n*m;
return g;
}
int main()
{
int a, b;
printf("Enter numbers a, and b: ");
scanf("%d %d", &a, &b);
printf("Here is ur answer: %d", random_fun(a, b));
return 0;
}
这意味着现在您在两个单独的文件中具有相同的功能。当你编译它们时,链接器会看到两个有效的函数random_fun
,它根本不知道使用哪个函数。
有两种方法可以解决这个问题。
在这种情况下,您需要创建另一个文件,例如function.h
:
// random.h
int random_fun(int n, int m);
然后,在main.c
中,您包含标题而不是.c:
#include <stdio.h>
#include "function.h" // <-- .h, not .c
int main()
{
int a, b;
printf("Enter numbers a, and b: ");
scanf("%d %d", &a, &b);
printf("Here is ur answer: %d", random_fun(a, b));
return 0;
}
这样,您将在两个文件中只有一个random_fun
函数,链接器不会混淆。
extern
关键字在main.c
中,您可以将random_fun
功能定义为外部功能。它基本上告诉编译器该函数存在于某处,稍后将由链接器解析。
#include <stdio.h>
extern int random_fun(int n, int m);
int main()
{
int a, b;
printf("Enter numbers a, and b: ");
scanf("%d %d", &a, &b);
printf("Here is ur answer: %d", random_fun(a, b));
return 0;
}
同样,在这种情况下,两个文件中只有一个random_fun
函数,链接器不会混淆。
根据经验,我会说除非你绝对需要,否则你永远不会包含.c
个文件。 (我很难想象何时需要它。)