我如何理解这个编译错误:“...的多重定义”

时间:2011-10-13 16:24:36

标签: c linux unix gcc

我正在完成考试作业。它将在近6个小时内到期。突然,我的程序将不再编译此错误消息:

gcc -g -D DEBUG -c -o obj/stringops.o src/stringops.c
gcc -g -D DEBUG -c -o obj/arrayops.o src/arrayops.c
gcc -g -D DEBUG -c -o obj/fileops.o src/fileops.c
gcc -g -D DEBUG -c -o obj/builtins.o src/builtins/*.c
gcc -g -D DEBUG -c -o obj/tomashell.o src/tomashell.c
gcc -g -D DEBUG -o bin/tomashell \
                obj/stringops.o obj/arrayops.o obj/fileops.o obj/builtins.o \
                obj/tomashell.o
obj/tomashell.o: In function `n_processes':
/root/sc/tomashell/src/safefork.c:11: multiple definition of `h_meta'
obj/builtins.o:/root/sc/tomashell/src/builtins/history.c:4: first defined here
obj/tomashell.o: In function `n_processes':
/root/sc/tomashell/src/safefork.c:11: multiple definition of `h_meta_len'
obj/builtins.o:/root/sc/tomashell/src/builtins/history.c:4: first defined here
collect2: ld returned 1 exit status
make: *** [bin/tomashell] Error 1

在此文件中:

#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/errno.h>

extern int errno;

#define MAX_PROCESSES 6

static int n_processes(void)
{ // <- THIS IS LINE 11
    return system("exit `ps | wc -l`")/256;
}


pid_t safefork(void)
{
  static int n_initial = -1;

  if (n_initial == -1)
    n_initial = n_processes();
  else if (n_processes() >= n_initial+MAX_PROCESSES) {
    sleep(2);
    errno = EAGAIN;  return (pid_t)-1;
  }

  return fork();
}

有人请帮助我或杀了我。我不想生活在可能出现这种错误的世界。

对可能出错的任何想法?

builtins/history.c
builtins/history.h

5 个答案:

答案 0 :(得分:3)

正如我在评论中提到的,问题在于h_metah_meta_len的多个定义 - 是因为它们是在.h文件中定义的,该文件包含在多个翻译中单位,或由于.c(变量的定义,直接或包含在.h中)包含在另一个.c中。包含防护可以避免编译错误,但不会导致链接错误。

这让我看到了奇怪的错误消息:您可以在链接时间获得这些消息。链接器对目标文件进行操作,目标文件包含.c文件中的代码及其包含的所有文件。因此,假设h_meta和朋友没有直接在两个.c文件中定义,那么链接器只能为您提供有用的信息。在VC中,您只会收到一条消息,告诉您有多个定义和目标文件列表(而不是.c)。

因此,鉴于定义来自上述.c文件中包含的文件,定义中没有实际的行号。我猜GCC只是默认为源头的开头。

答案 1 :(得分:2)

您的头文件history.h包含变量声明。您必须将此文件包含在多个源文件中。这会导致变量多次声明。相反,您应该查看extern关键字或重新考虑您的实施。

答案 2 :(得分:2)

与其他人所说的一样,你不应该在标题中“定义”(隐式或显式地为空间分配空间)。

此示例可能有所帮助:

#ifndef HISTORY
#define HISTORY
...

/* Bad!  Don't actually DEFINE (allocate space for) variables in a header!
 * h_metablock* h_meta = NULL;
 * int h_meta_len = 0;
 */

/* Better: declare "extern", then define in exactly ONE module (e.g. "main.c") */
extern h_metablock* h_meta;
extern int h_meta_len;
...

当然,同样适用于您在.c / .cpp文件中定义的任何全局变量。

全局只能完全“定义”一次

答案 3 :(得分:1)

C中的程序只能为每个对象(变量的存储空间)提供一个定义(为其分配值的声明)。

您的头文件包含多个变量的定义,当包含在多个不同的转换单元中时,会导致链接器抛出此错误。您的标题文件至少包含两个翻译单元,一个用于 history.c ,另一个用于 tomashell.c

有关定义here的内容的更多信息。

答案 4 :(得分:0)

比较safefork.c:11和history.c:4

看起来你的符号被定义了两次。