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

时间:2022-02-04 00:02:31

I'm working on my exam assignment. It's due in almost 6 hours. Suddenly my program won't compile anymore with this error message:

我正在完成考试任务。它将在近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

In this file:

在这个文件中:

#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();
}

Someone please help me or kill me. I don't want to live in a world where this sort of error is possible.

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

Any ideas to what might be wrong?

什么想法可能是错的?

builtins/history.c
builtins/history.h

5 个解决方案

#1


2  

Like the others have said, you should not "define" (either implicitly or explicitly allocate space for) a variable in your headers.

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

This example might help:

此示例可能有所帮助:

#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;
...

The same, of course, goes for any globals you might define in your .c/.cpp files.

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

A global can only be "defined" exactly once.

全局只能被“定义”一次。

#2


3  

As I've mentioned in my comment, the problem is with multiple definitions of h_meta and h_meta_len - be it due to them being defined in a .h file that's included in more than one translation unit, or due to .c (with the definition of the variables, either directly or in an included .h) being included in another .c. Include guards will save you from compilation errors, but not from link errors.

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

And this brings me to the weird error messages: You get those at link time. The linker operates on object files, which contain code from a .c file and all the files it had included. So, assuming h_meta and friend are not defined directly in two .c files, there's only so much the linker can do to provide you useful information. In VC, you'd only get a message telling you that there are multiple definitions, and the list of object files (rather than .c).

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

So, given the definitions come from files included in the mentioned .c files, there's no actual line number for the definitions. I guess GCC just defaults to the beginning of the source.

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

#3


2  

Your header file history.h contains variable declarations. You must be including this file in multiple source files. This causes the variable to be declared multiple times. Instead you should either look into the extern keyword or reconsider your implementation.

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

#4


1  

A program in C can have only one definition (declaration which assigns a value) for each object (storage space for a variable).

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

Your header file contains definitions for several variables, which when included in several different translation units results in the linker throwing this error. Your header file is included in at least two translation units, one for history.c, and another one for tomashell.c.

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

More information on what constitutes a definition here.

有关此定义的更多信息,请参见此处。

#5


0  

Compare safefork.c:11 and history.c:4

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

Looks like your symbol is being defined twice.

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

#1


2  

Like the others have said, you should not "define" (either implicitly or explicitly allocate space for) a variable in your headers.

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

This example might help:

此示例可能有所帮助:

#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;
...

The same, of course, goes for any globals you might define in your .c/.cpp files.

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

A global can only be "defined" exactly once.

全局只能被“定义”一次。

#2


3  

As I've mentioned in my comment, the problem is with multiple definitions of h_meta and h_meta_len - be it due to them being defined in a .h file that's included in more than one translation unit, or due to .c (with the definition of the variables, either directly or in an included .h) being included in another .c. Include guards will save you from compilation errors, but not from link errors.

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

And this brings me to the weird error messages: You get those at link time. The linker operates on object files, which contain code from a .c file and all the files it had included. So, assuming h_meta and friend are not defined directly in two .c files, there's only so much the linker can do to provide you useful information. In VC, you'd only get a message telling you that there are multiple definitions, and the list of object files (rather than .c).

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

So, given the definitions come from files included in the mentioned .c files, there's no actual line number for the definitions. I guess GCC just defaults to the beginning of the source.

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

#3


2  

Your header file history.h contains variable declarations. You must be including this file in multiple source files. This causes the variable to be declared multiple times. Instead you should either look into the extern keyword or reconsider your implementation.

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

#4


1  

A program in C can have only one definition (declaration which assigns a value) for each object (storage space for a variable).

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

Your header file contains definitions for several variables, which when included in several different translation units results in the linker throwing this error. Your header file is included in at least two translation units, one for history.c, and another one for tomashell.c.

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

More information on what constitutes a definition here.

有关此定义的更多信息,请参见此处。

#5


0  

Compare safefork.c:11 and history.c:4

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

Looks like your symbol is being defined twice.

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