Множественное определение и первое определение в моей программе на C

Я читаю APUE (" Расширенное программирование Стивенса в среде UNIX "), поэтому существует файл "apue.h", который включает в себя некоторую объявленную функцию самоопределения. Я пишу файл с именем "wait.c", который определяет функции WAIT_CHILD, WAIT_PARENT объявлен в "apue.h", и 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 просто используется не определено, так в чем проблема??

wait.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 ответа

Решение

Источник с веб-сайта книги APUE содержит эти три объявления (среди многих других) в apue.h:

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

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

Судя по сообщению об ошибке вашего компилятора, не только err_ret() определяется, это на самом деле определяется дважды, один раз в исходном файле wait.c и один раз в вашем исходном файле 14.6.c, Вам нужно будет решить, какое из этих определений (если одно из них) является правильным, и удалить другое, либо решить, что вы не можете использовать код в wait.c с вашей программой в 14.6.c, Может быть еще лучше поставить err_ret() и друзья в свой собственный исходный файл. В источнике err_*() функции находятся в lib/error.c,


Я не переопределил функции err_*()так что я думаю, что я использую lib/error.c исходный файл. И в apue.h есть:

#ifndef _APUE_H
#define _APUE_H

так что я думаю, что это не будет определено дважды.

Если ваш TU (блок перевода) делает #include "lib/error.c"тогда ваш TU определяет функции. Компилятор C видит исходный код, содержащий ваш исходный код, а также заголовки, которые вы включаете, а также (гипотетически) код в lib/error.c, Вы просто не должны включать этот исходный файл; Вы должны скомпилировать его отдельно и связать объектный файл с вашей программой. apue.h заголовок объявляет err_*() функции, чтобы вы могли использовать их в своем коде. Вы должны скомпилировать lib/error.c отдельно и свяжите это со своим wait.o а также 14.6.o файлы.

Крайне важно понимать разницу между определением переменной или функции (фактически выделением памяти для нее) и объявлением переменной или функции (сообщая компилятору, что функция или переменная существует, но что она здесь не определена - как в 'this объявление не определяет его ", даже если следующая строка в исходном файле определяет его). Заголовки должны предоставлять объявления и не должны давать определения (большую часть времени - это достаточно хорошее правило, пока вы не знаете достаточно, чтобы знать, когда и как нарушать правило).


Но то, что я делаю, это просто #include "apue.h" когда я пишу свой исходный файл. Я не совсем понимаю, как отдельно компилировать lib/error.c,

Похоже, вам нужны три исходных файла в вашей компиляции и в строке ссылки:

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

Или вы можете сделать это в отдельных операциях:

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

Вам могут понадобиться дополнительные флаги компилятора (-I или же -D параметры, например), или дополнительные библиотеки и параметры компоновщика (-llib а также -L /directory/lib варианты, например).

Если ваши исходные файлы 14.6.c и wait.c содержат #include "apue.h" и не включайте другие исходные файлы (поэтому нет #include "lib/error.c" или что-нибудь подобное - и 14.6.c не включает ваш wait.c ни наоборот), то проблем не должно быть.

Однако вы столкнулись с проблемами, и мы не можем увидеть ваш источник или команду связывания, а это значит, что мы должны попытаться угадать, что вы сделали неправильно. Мы можем придумать всевозможные странные примеры того, что вы делаете, но мы, скорее всего, ошибемся.

Таким образом, сводя код к минимуму, покажите нам, какие файлы вы компилируете и как вы их компилируете.

Не определяйте функции или переменные в заголовочных файлах. объявите их в заголовочных файлах, определите их в исходных файлах.c.

вам нужно создать отдельный исходный файл для определений и скомпилировать его отдельно.

также помните о разнице между объявлением глобальных переменных и определением. Если вам нужно объявить переменную, которая используется несколькими файлами.c, вы должны сказать:

extern int err__ret;

объявить переменную (как внешнюю переменную) в заголовочном файле, а затем добавить:

int err_ret;

в один файл.c, чтобы определить его.

Также обратите внимание, что любой файл.c, который определяет переменную или функцию, должен также включать файл.h, который его объявляет. Это приведет к тому, что компилятор выдаст ошибку, если есть какие-либо расхождения между объявлением и определением.

Пожалуйста, покажите запись wait.h для err_ret(), вы можете скрыть другие строки, если хотите. Никто не просит вас скомпрометировать ваш NDA:)(каламбур). Вы также объявили err_ret() снова в wait.c? если у вас есть, то он не скомпилируется.(Я думаю, в этом и заключается проблема)

сначала выполните предварительную обработку, чтобы найти несколько определений, как показано ниже:

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

просмотрите выходные данные и номера строк, чтобы узнать, где именно функции объявлены и определены.

Я встретил подобную проблему, когда я собирал sigsetjmp.c, Наконец я нахожу причину в том, что у меня было #include "error.c" в моем apue.h, в результате чего при компиляции нескольких файлов c каждый файл включает apue.h, а затем включить error.c, привести к множественному определению ошибки err_ret.

Вот мое предложение:

  1. Не включайте файл определения функции c в заголовочный файл (apue.h).
  2. Требуется другой файл c в командной строке gcc или Makefile в порядке.

    например: gcc sigsetjmp.c pr_mask.c error.c

Надеюсь, это поможет.

Другие вопросы по тегам