我有个问题.我写了这段代码,ahac和main.c:
档案:啊
#ifndef _a_H
#define _a_H
int poly (int a, int b, int c, int x);
int square (int x)
{
return x*x;
}
#endif // _a_H
Run Code Online (Sandbox Code Playgroud)
档案:ac
#include "a.h"
int poly (int a, int b, int c, int x)
{
return a*square(x) + b * x +c;
}
Run Code Online (Sandbox Code Playgroud)
file:main.c
#include <stdio.h>
#include "a.h"
int main()
{
int p1 = poly1 (1 ,2 , 1, 5);
int p2 = poly2 (1 ,1 , 3, 5);
printf ("p1 = %d, p2 = %d\n", p1, p2);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我收到一个错误:
/tmp/ccKKrQ7u.o:在函数'square'中:
main.c :(.text + 0x0):'square'/
tmp/ccwJoxlY.o:ac :(.text+0x0)的多重定义:首先在这里定义
collect2 :ld返回1退出状态
所以我将函数square的实现移动到ac文件,它的工作原理.
有人知道为什么吗?
感谢名单
一般来说,*.c文件被编译成*.o文件,*.o文件被链接以构建可执行文件.*.h文件未编译,它们以文本形式包含在*.c文件中,它们是#included.
因此,通过#including"ah"两次,在两个单独的*.c文件中,您已将square()的定义放入两个单独的文件中.编译完成后,最终会得到两个square()副本,每个*.o文件中有一个副本.然后,当您链接它们时,链接器会看到这两个文件,并生成错误.
怎么避免这个?你已经发现了这个.不要将函数定义放在*.h文件中.将它们放在*.c文件中,只将函数声明放在*.h文件中.
当square()在标头中时,它同时包含在ac和main.c中,因此每个对应的目标文件都有自己的square(),但是没有static修饰符,它们具有完全相同的名称。将其移至ac意味着仅定义一次。
如果您确实要在头文件中使用该函数,则可以使用静态内联对其进行定义,因此:
static inline int square (int x)
{
return x*x;
}
Run Code Online (Sandbox Code Playgroud)
静态意味着每个包含.h的.c文件都将拥有自己的square()版本,内联意味着代码将被内联删除,并且实际上不会发生任何函数调用,这可能就是您想要的
发生这种情况是因为您的C编译器将每个.c文件构建到对象(.o)文件中,然后链接目标文件以生成可执行文件..c文件的内容及其包含的所有文件称为编译单元.
您的示例有两个编译单元:
main.c,包括stdio.h和a.h→编译到main.oa.c,包括a.h→编译到ao链接器(ld)然后尝试链接.o文件,但发现它们都定义square(),因为它在共享中a.h- 因此是错误.这就是为什么,正如一些人已经指出的那样,你不应该把函数定义放在头文件中.
如果您已nm安装该实用程序(您应该具有该实用程序),则可以运行
$ nm main.o
$ nm a.o
Run Code Online (Sandbox Code Playgroud)
在shell中看到square两个文件中都存在.
(编辑:我想到的这个词实际上是翻译单元,但是在搜索时它们似乎意味着几乎相同的东西.)