0

APUE (Stevens の「UNIX 環境での高度なプログラミング」) を読んでいるので、宣言された自己定義関数を含むファイル「apue.h」があります。WAIT_CHILD「apue.h」で宣言された関数を定義する「wait.c」という名前のファイルを作成しWAIT_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ソースファイルで定義します。

定義用に別のソースファイルを作成し、それを個別にコンパイルする必要があります。

また、グローバル変数の宣言と定義の違いにも注意してください。複数の.cファイルで使用される変数を宣言する必要がある場合は、次のように言う必要があります。

extern int err__ret;

ヘッダーファイルで変数を(外部変数として)宣言するには、次を追加します。

int err_ret;

1つの.cファイルに、それを定義します。

また、変数または関数を定義する.cファイルには、それを宣言する.hファイルも含める必要があります。これにより、宣言と定義の間に不一致がある場合、コンパイラはエラーを生成します。

于 2012-04-05T14:12:03.750 に答える
1

err_ret() の wait.h のエントリを表示してください。必要に応じて他の行を隠すことができます。誰もあなたのNDAを妥協するようにあなたに求めていません:)(しゃれが意図されています). また、wait.c で err_ret() を再度宣言しましたか? あなたが持っている場合、それはコンパイルされません.(私はそこに問題があると推測しています)

以下のような複数の定義を見つけるために、最初に前処理を行います。

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

出力と行番号を調べて、関数が正確に宣言および定義されている場所を見つけます。

于 2012-04-05T14:29:10.910 に答える
1

APUE ブックの Web サイトのソースには、次の 3 つの宣言が (他の多くの宣言とともに) 含まれていapue.hます。

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

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

コンパイラからのエラー メッセージから判断すると、 がerr_ret()定義されているだけでなく、実際にはソース ファイルwait.cで 1 回、ソース ファイルで 1 回、2 回定義されています14.6.c。これらの定義のどちらが正しいかを判断し、もう一方を削除するか、 のコードwait.cを のプログラムで使用できないと判断する必要があります14.6.cerr_ret()と友達を独自のソース ファイルに入れる方が良いかもしれません。ソースでは、err_*()関数は にありlib/error.cます。


関数の再定義はしていないので、ソースファイルerr_*()を使用していると思います。lib/error.cそしてapue.hそこには:

#ifndef _APUE_H
#define _APUE_H

したがって、2回定義されることはないと思います。

TU (翻訳単位) が#include "lib/error.c"の場合、TU は関数を定義しています。C コンパイラは、ソースを含むソース コードと、インクルードするヘッダー、および (仮定的に) のコードを認識しますlib/error.c。そのソース ファイルをインクルードするべきではありません。個別にコンパイルし、オブジェクト ファイルをプログラムにリンクする必要があります。apue.hヘッダーは関数を宣言するためerr_*()、コードで使用できます。個別にコンパイルし、ファイルlib/error.cとリンクする必要がwait.oあり14.6.oます。

変数または関数を定義する (実際にストレージを割り当てる) ことと、変数または関数を宣言する (関数または変数が存在するが、ここでは定義されていないことをコンパイラーに伝える) ことの違いを理解することが重要です。ソースファイルの次の行で定義されていても、宣言では定義されていません)。ヘッダーは宣言を提供する必要があり、定義を提供するべきではありません (ほとんどの場合 — ルールを破るタイミングと方法を十分に理解するまでは、これで十分なルールです)。


しかし、私がしているのは#include "apue.h"、ソース ファイルを作成するときだけです。を個別にコンパイルする方法がよくわかりませんlib/error.c

したがって、コンパイルとリンクの行に 3 つのソース ファイルが必要なようです。

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その逆)、問題に遭遇することはありません。

ただし、問題が発生しており、ソースまたはリンク コマンドが表示されません。つまり、何が間違っているかを推測する必要があります。あなたがしていることのあらゆる種類の風変わりな例を考案することができますが、私たちは間違っている可能性が最も高い.

したがって、コードを最小限に抑えて、コンパイルしているファイルとそれらをどのようにコンパイルしているかを示してください。

于 2012-04-05T14:25:04.517 に答える
0

をコンパイルしたときに、同様の問題に遭遇しましたsigsetjmp.c。最後に、その理由は、#include "error.c"複数apue.hの c ファイルをコンパイルすると、各ファイルに includeapue.hがあり、次に includeerror.cがあり、err_ret エラーの複数の定義につながることが原因であることがわかりました。

これが私の提案です:

  1. 関数定義の c ファイルを head ファイル ( ) に含めないでくださいapue.h
  2. gcc コマンド ラインまたは Makefile で必要なその他の c ファイルは問題ありません。

    例えば:gcc sigsetjmp.c pr_mask.c error.c

この助けを願っています。

于 2015-12-01T03:15:12.573 に答える