Множественное определение и первое определение в моей программе на 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.
Вот мое предложение:
- Не включайте файл определения функции c в заголовочный файл (
apue.h
). Требуется другой файл c в командной строке gcc или Makefile в порядке.
например:
gcc sigsetjmp.c pr_mask.c error.c
Надеюсь, это поможет.