在C中定义两次函数

时间:2010-09-27 16:25:47

标签: c function header

我有一个问题。我写了这段代码,a.h。 a.c和main.c:

文件:a.h

#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

文件:a.c

#include "a.h"
int poly (int a, int b, int c, int x)
{
     return a*square(x) + b * x +c;
}

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;
}

我收到了一个错误:

  

/tmp/ccKKrQ7u.o:在函数'square'中:
  main.c :(。text + 0x0):'square'的多重定义
  /tmp/ccwJoxlY.o:a.c:(.text+0x0):首先在此定义
  collect2:ld返回1退出状态

所以我将函数square的实现移动到了a.c文件,它可以工作。

有人知道为什么吗?

感谢名单

6 个答案:

答案 0 :(得分:8)

一般来说,* .c文件被编译成* .o文件,* .o文件被链接以构建可执行文件。 * .h文件未编译,它们以文本形式包含在* .c文件中,包含#included。

因此,通过#including“a.h”两次,在两个单独的* .c文件中,您已将square()的定义放入两个单独的文件中。编译完成后,最终会得到两个square()副本,每个* .o文件中有一个副本。然后,当您链接它们时,链接器会看到这两个文件,并生成错误。

如何避免这种情况?你已经发现了这个。不要将函数定义放在* .h文件中。将它们放在* .c文件中,只将函数声明放在* .h文件中。

答案 1 :(得分:6)

不要将代码放在头文件中。这两个.c文件都包含a.h,因此它们都会获得square的实现,因此您的链接器会抱怨。

答案 2 :(得分:5)

这是因为您的C编译器将每个.c文件构建到对象(.o)文件中,然后链接目标文件以生成可执行文件。 .c文件的内容及其包含的所有文件称为编译单元

您的示例有两个编译单元:

  • main.c,包括stdio.ha.h→汇编到main.o
  • a.c,包括a.h→编译到a.o

链接器(ld)然后尝试链接.o文件,但发现它们都定义square(),因为它位于共享a.h中 - 因此出错。这就是为什么,正如一些人已经指出的那样,你不应该把函数定义放在头文件中。

如果您安装了nm实用程序(您应该拥有),则可以运行

$ nm main.o
$ nm a.o
在shell中

看到两个文件中都存在square

(编辑:我想到的这个词实际上是翻译单元,但是在搜索它们时似乎意味着几乎相同的事情。)

答案 3 :(得分:4)

当标题中有square()时,它包含在ac和main.c中,因此每个相应的目标文件都有自己的square(),但是如果没有静态修饰符,则它们具有完全相同的名字。将它移动到a.c意味着它只定义一次。

如果您真的想要头文件中的函数,可以使用静态内联来定义它:

static inline int square (int x)
{
       return x*x;
}

静态意味着包含.h的每个.c文件都有自己的square()版本,内联意味着代码将被内联删除,并且实际上不会发生函数调用,这可能就是你想要的这里

答案 4 :(得分:1)

您不能在头文件中编写实现(函数体),否则链接器将找到对该函数的多个引用。

通常,只在头文件中放置声明,而不是定义。

答案 5 :(得分:0)

你已经回答了自己的问题:你已经在每个包含a.h的编译文件中定义了两次方块。

为了避免这种情况,你可以使方形成为静态函数

static int square (int x)
{
   return x*x;
}

并添加编译器使用的内联提示,例如: inline__inline