0

我正在阅读 APUE(Stevens 的“ UNIX 环境中的高级编程”),所以有一个文件“apue.h”,其中包含一些声明的自定义函数。我编写了一个名为“wait.c”的文件,它定义了在“apue.h”中声明的函数WAIT_CHILDWAIT_PARENT而 14.6.c 是主要函数。

tmp/cciYhMd7.o: In function `err_ret':
14.6.c:(.text+0x0): multiple definition of `err_ret'
/tmp/ccO4WyJS.o:wait.c:(.text+0x0): first defined here

err_ret只是使用未定义,所以有什么问题?

等待.c

#include "apue.h"

static volatile sig_atomic_t sigflag;
static sigset_t newmask, oldmask, zeromask;

static void
sig_usr(int signo)
{
    sigflag = 1;
}

void
TELL_WAIT(void)
{
    if(signal(SIGUSR1, sig_usr) == SIG_ERR)
      err_sys("signal(SIGUSR1) error");
    if(signal(SIGUSR2, sig_usr) == SIG_ERR)
      err_sys("signal(SIGUSR2) error");

    sigemptyset(&zeromask);
    sigemptyset(&newmask);

    sigaddset(&newmask, SIGUSR1);
    sigaddset(&newmask, SIGUSR2);

    if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
      err_sys("SIG_BLOCK error");
}

void
TELL_PARENT(pid_t pid)
{
    kill(pid, SIGUSR2);
}

void
WAIT_PARENT(void)
{
    while(sigflag == 0)
      sigsuspend(&zeromask);
    sigflag = 0;

    if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
      err_sys("SIG_SETMASK error");
}

void
TELL_CHILD(pid_t pid)
{
    kill(pid, SIGUSR2);
}

void
WAIT_CHILD(void)
{
    while(sigflag == 0)
      sigsuspend(&zeromask);
    sigflag = 0;

    if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
      err_sys("SIG_SETMASK error");
}

上面的代码是我的“wait.c”源文件。我只是用err_sys. 以下是我收到的链接命令行和链接器错误消息:

$ gcc -o a.out wait.c 14.6.c
/tmp/ccZ5F3Pn.o: In function `err_ret':
14.6.c:(.text+0x0): multiple definition of `err_ret'
/tmp/cc5EXGbf.o:wait.c:(.text+0x0): first defined here
/tmp/ccZ5F3Pn.o: In function `err_sys':
14.6.c:(.text+0x38): multiple definition of `err_sys'
/tmp/cc5EXGbf.o:wait.c:(.text+0x38): first defined here
/tmp/ccZ5F3Pn.o: In function `err_exit':
14.6.c:(.text+0x76): multiple definition of `err_exit'
/tmp/cc5EXGbf.o:wait.c:(.text+0x76): first defined here
/tmp/ccZ5F3Pn.o: In function `err_dump':
14.6.c:(.text+0xaf): multiple definition of `err_dump'
/tmp/cc5EXGbf.o:wait.c:(.text+0xaf): first defined here
/tmp/ccZ5F3Pn.o: In function `err_msg':
14.6.c:(.text+0xe6): multiple definition of `err_msg'
/tmp/cc5EXGbf.o:wait.c:(.text+0xe6): first defined here
/tmp/ccZ5F3Pn.o: In function `err_quit':
14.6.c:(.text+0x116): multiple definition of `err_quit'
/tmp/cc5EXGbf.o:wait.c:(.text+0x116): first defined here
/tmp/ccZ5F3Pn.o: In function `TELL_WAIT':
14.6.c:(.text+0x5fe): multiple definition of `TELL_WAIT'
/tmp/cc5EXGbf.o:wait.c:(.text+0x272): first defined here
/tmp/ccZ5F3Pn.o: In function `TELL_CHILD':
14.6.c:(.text+0x72e): multiple definition of `TELL_CHILD'
/tmp/cc5EXGbf.o:wait.c:(.text+0x3a2): first defined here
/tmp/ccZ5F3Pn.o: In function `WAIT_PARENT':
14.6.c:(.text+0x6d8): multiple definition of `WAIT_PARENT'
/tmp/cc5EXGbf.o:wait.c:(.text+0x34c): first defined here
/tmp/ccZ5F3Pn.o: In function `TELL_PARENT':
14.6.c:(.text+0x6bd): multiple definition of `TELL_PARENT'
/tmp/cc5EXGbf.o:wait.c:(.text+0x331): first defined here
/tmp/ccZ5F3Pn.o: In function `WAIT_CHILD':
14.6.c:(.text+0x749): multiple definition of `WAIT_CHILD'
/tmp/cc5EXGbf.o:wait.c:(.text+0x3bd): first defined here
collect2: ld returned 1 exit status
4

4 回答 4

2

不要在头文件中定义函数或变量。在头文件中声明它们,在 .c 源文件中定义它们。

you need to create a separate source file for the definitions and compile it separately.

also, be aware of the difference between declaration of global variables and deifnition. If you need to declare a variable that is used by multiple .c files, you must say:

extern int err__ret;

to declare the variable (as an external variable) in your header file, then add:

int err_ret;

to one .c file, to define it.

Note also, any .c file that defines a variable or function should also include the .h file that declares it. This will cause the compiler to produce an error if there are any discrepancies between the declaration and the definition.

于 2012-04-05T14:12:03.750 回答
1

The source from the APUE book's web site has these three declarations (amongst many others) in apue.h:

void    err_ret(const char *, ...);

void    WAIT_PARENT(void);
void    WAIT_CHILD(void);

Judging from the error message from your compiler, not only is err_ret() defined, it is in fact defined twice, once in your source file wait.c and once in your source file 14.6.c. You will need to decide which (if either) of those definitions is correct, and remove the other, or decide that you can't use the code in wait.c with your program in 14.6.c. It might be better still to put err_ret() and friends into their own source file. In the source, the err_*() functions are in lib/error.c.


I didn't redefine the functions err_*(), so I think I use the lib/error.c source file. And in apue.h there's:

#ifndef _APUE_H
#define _APUE_H

so I think it won't defined twice.

If your TU (translation unit) does #include "lib/error.c", then your TU is defining the functions. The C compiler sees the source code containing your source plus the headers you include plus (hypothetically) the code in lib/error.c. You simply shouldn't be including that source file; you should compile it separately and link the object file into your program. The apue.h header declares the err_*() functions so you can use them in your code. You are expected to compile lib/error.c separately and link it with your wait.o and 14.6.o files.

It is crucial to understand the difference between defining a variable or function (actually allocating the storage for it) and declaring a variable or function (telling the compiler that the function or variable exists, but that it is not defined here — as in 'this declaration does not define it', even if the next line in the source file does define it). Headers should provide declarations and should not provide definitions (most of the time — it's a good enough rule for now, until you know enough to know when and how to break the rule).


But what I do is just #include "apue.h" when I write my source file. I don't quite understand how to separately compile lib/error.c.

So, it sounds like you need three source files in your compile and link line:

gcc -o 14.6 14.6.c wait.c lib/error.c

Or you might do it in separate operations:

gcc -c 14.6.c
gcc -c wait.c
gcc -c lib/error.c -o error.o
gcc -o 14.6 14.6.o wait.o error.o

You might need extra compiler flags (-I or -D options for example), or extra libraries and linker options (-llib and -L /directory/lib options, for example).

If your source files 14.6.c and wait.c contain #include "apue.h" and do not include other source files (so no #include "lib/error.c" or anything similar — and 14.6.c does not include your wait.c nor vice versa), then you should not run into problems.

However, you are running into problems, and we can't see your source or your linking command, which means we have to try and guess what you've done wrong. We can devise all sorts of outlandish examples of what you might be doing, but we're most likely to be wrong.

So, keeping the code to a minimum, show us which files you are compiling and how you are compiling them.

于 2012-04-05T14:25:04.517 回答
1

please show wait.h's entry of err_ret(), you can obscure other lines if you want. No one is asking you to compromise your NDA :)(pun intended). also have you declared err_ret() again in wait.c? if you have then it won't compile.(i'm guessing that's where the problem lies)

do preprocessing first to find multiple definitions like below:

$gcc -E wait.c | grep -n 'err_ret'
$gcc -E 14.6.c | grep -n 'err_ret'

look through the output and line numbers to find out where exactly the functions are declared and defined.

于 2012-04-05T14:29:10.910 回答
0

I met the similar problem when I compiling my sigsetjmp.c. Finally I find the reason is that I had #include "error.c" in my apue.h, which result in when compiling multiple c files, each file include apue.h, and then include error.c, lead to the multiple definition of the err_ret error.

Here's my suggestion:

  1. Don't include any function definition c file in head file (the apue.h).
  2. Required other c file in gcc command line or Makefile is OK.

    eg: gcc sigsetjmp.c pr_mask.c error.c

Hope this help.

于 2015-12-01T03:15:12.573 回答