You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GCC编译多C源文件时出现多重定义错误求助

C程序编译多重定义错误排查

我编写了一个包含两个源文件的C程序:main.c(含main函数)、sorting.c(含函数定义),还有defs.h头文件用于声明函数和共享变量,避免来回传递变量。但执行编译命令后出现大量多重定义错误,尝试移除部分头文件、添加头文件保护、分开编译链接都没解决,请问问题出在哪?

代码文件

main.c

#include <stdio.h>
#include "defs.h"
#include "sorting.c"

int main(int argc, char **argv){

    listLength = 0;/*this is a load of barnacles*/
    EOFFlag = 1;

    input = fopen(argv[1], "r");

    if(input == NULL){
        printf("Could not open requested file.\n");
        return -1;
    }

    while(EOFFlag){
        sortNextWord();
    }

    if(FULLLISTCONSEQUENCES){
        for(genericIterator = 0; genericIterator < USHRT_MAX + 1; genericIterator++){
            printf("%d: %s; %d", genericIterator + 1, wordlist[genericIterator], wordcount[genericIterator]);
        }
    }else{
        for(genericIterator = 0; genericIterator < listLength; genericIterator++){
            printf("%d: %s; %d", genericIterator + 1, wordlist[genericIterator], wordcount[genericIterator]);
        }
    }

    return 1;
}

sorting.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "defs.h"

int sortNextWord(){
    
    getNextWord();
    if(wordHolder[0] != '\0')/*checks to ensure that getNextWord didn't get an empty string*/
        listMatch();
    return 1;
}
int getNextWord(){
    char charStore;
    char returnFlag = 0;

    genericIterator = 0;

    while(genericIterator != USHRT_MAX){

        switch(charStore = getc(input)){

        case EOF:
            EOFFlag = 0;
            goto exitcond;/* checks for EOF or whitespace, exits loop if found*/
        case ' ':
        case '\n':
        case '\t':
            goto exitcond;
        default:
            wordHolder[genericIterator++] = charStore;/* otherwise it writes the character it read to the next available spot */
            break;
        }
    }
exitcond:
    wordHolder[genericIterator] = '\0';
    wordlen = genericIterator;
    return 1;
}

int listMatch(){/* runs through wordlist to find a matching word. If found, increments the respective wordcount entry, otherwise, creates new entry in wordlist */
    for(genericIterator = 0; genericIterator < listLength; genericIterator++){
        if(strcmp(wordHolder, wordlist[genericIterator])){
            ++wordcount[genericIterator];
            goto foundmatch;
        }
    }
    addToList();
foundmatch:
    return 1;
}

int addToList(){ /*adds word to next available spot in wordlist*/

    char *string;
    if(FULLLISTCONSEQUENCES) /*doesnt do anything if wordlist is full */
        return 0; /* John Freeman, who was Go */
    if(listLength == USHRT_MAX)
        FULLLISTCONSEQUENCES = 1;

    string = malloc((wordlen + 1) * sizeof(char));
    string[0] = '\0';

    strncat(string, wordHolder, USHRT_MAX + 1);

    wordcount[listLength] = 1;
    wordlist[listLength++] = string;

    return 1;
}

defs.h(忽略堆排序相关内容)

#ifndef DEFS_H
#define DEFS_H
#include <limits.h>
#include <stdio.h>

char *wordlist[USHRT_MAX + 1];
int wordcount [USHRT_MAX + 1];
unsigned short listLength;
unsigned short genericIterator;
FILE *input;

/*heapsort goes here */

char wordHolder[USHRT_MAX +  1];
unsigned short wordlen;
char EOFFlag;
char FULLLISTCONSEQUENCES;

int heapsort();
int buildMaxHeap();
int restoreMaxHeap();
int swap(unsigned short, unsigned short);
unsigned short getParent(unsigned short);
unsigned short getRightChild(unsigned short);
unsigned short getLeftChild(unsigned short);

int sortNextWord(); 
int getNextWord(); 
int listMatch();
int addToList();

#endif

编译命令

gcc -o wordsort main.c sorting.c

编译错误信息

/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0x0): multiple definition of `wordlist'; /tmp/cc3dFw3Q.o:(.bss+0x0): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0x80000): multiple definition of `wordcount'; /tmp/cc3dFw3Q.o:(.bss+0x80000): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xc0000): multiple definition of `listLength'; /tmp/cc3dFw3Q.o:(.bss+0xc0000): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xc0002): multiple definition of `genericIterator'; /tmp/cc3dFw3Q.o:(.bss+0xc0002): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xc0008): multiple definition of `input'; /tmp/cc3dFw3Q.o:(.bss+0xc0008): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xc0020): multiple definition of `wordHolder'; /tmp/cc3dFw3Q.o:(.bss+0xc0020): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xd0020): multiple definition of `wordlen'; /tmp/cc3dFw3Q.o:(.bss+0xd0020): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xd0022): multiple definition of `EOFFlag'; /tmp/cc3dFw3Q.o:(.bss+0xd0022): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o:(.bss+0xd0023): multiple definition of `FULLLISTCONSEQUENCES'; /tmp/cc3dFw3Q.o:(.bss+0xd0023): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o: in function `sortNextWord':
main.c:(.text+0x0): multiple definition of `sortNextWord'; /tmp/cc3dFw3Q.o:sorting.c:(.text+0x0): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o: in function `getNextWord':
main.c:(.text+0x2a): multiple definition of `getNextWord'; /tmp/cc3dFw3Q.o:sorting.c:(.text+0x2a): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o: in function `listMatch':
main.c:(.text+0xdf): multiple definition of `listMatch'; /tmp/cc3dFw3Q.o:sorting.c:(.text+0xdf): first defined here
/usr/bin/ld: /tmp/cc8X0W8R.o: in function `addToList':
main.c:(.text+0x191): multiple definition of `addToList'; /tmp/cc3dFw3Q.o:sorting.c:(.text+0x191): first defined here
collect2: error: ld returned 1 exit status

错误原因

1. 源文件被重复编译

main.c里直接包含了sorting.c:#include "sorting.c"。这会导致编译main.c时,sorting.c的所有代码被插入到main.c中,生成的目标文件main.o里包含了sortNextWord、getNextWord等函数的定义。而编译时又把sorting.c作为单独的源文件传给gcc,sorting.o里也有这些函数的定义。链接阶段,链接器发现同一个函数被定义了两次,就会抛出多重定义错误。

2. 全局变量在头文件中直接定义

defs.h里直接定义了全局变量(比如char *wordlist[USHRT_MAX + 1];),而不是声明。头文件保护(#ifndef DEFS_H)只能防止同一个源文件重复包含头文件,但每个包含defs.h的源文件(main.c和sorting.c)都会生成这些变量的独立定义。链接时,两个目标文件里的同名全局变量冲突,导致多重定义错误。

解决方案

步骤1:移除源文件的包含

删除main.c中的#include "sorting.c",源文件不需要互相包含,链接时gcc会自动处理多个目标文件的合并。修改后的main.c开头应为:

#include <stdio.h>
#include "defs.h"

步骤2:修改头文件的变量声明

把defs.h里的全局变量定义改成声明,添加extern关键字,告诉编译器这些变量在其他源文件中定义:

#ifndef DEFS_H
#define DEFS_H
#include <limits.h>
#include <stdio.h>

extern char *wordlist[USHRT_MAX + 1];
extern int wordcount [USHRT_MAX + 1];
extern unsigned short listLength;
extern unsigned short genericIterator;
extern FILE *input;

/*heapsort goes here */

extern char wordHolder[USHRT_MAX +  1];
extern unsigned short wordlen;
extern char EOFFlag;
extern char FULLLISTCONSEQUENCES;

// 函数声明保持不变
int heapsort();
int buildMaxHeap();
int restoreMaxHeap();
int swap(unsigned short, unsigned short);
unsigned short getParent(unsigned short);
unsigned short getRightChild(unsigned short);
unsigned short getLeftChild(unsigned short);

int sortNextWord(); 
int getNextWord(); 
int listMatch();
int addToList();

#endif

步骤3:在一个源文件中定义全局变量

选择其中一个源文件(比如sorting.c),添加全局变量的定义(去掉extern),确保这些变量只被定义一次:
在sorting.c的开头(#include之后)添加:

char *wordlist[USHRT_MAX + 1];
int wordcount [USHRT_MAX + 1];
unsigned short listLength;
unsigned short genericIterator;
FILE *input;

char wordHolder[USHRT_MAX +  1];
unsigned short wordlen;
char EOFFlag;
char FULLLISTCONSEQUENCES;

步骤4:重新编译

执行原来的编译命令即可:

gcc -o wordsort main.c sorting.c

内容的提问来源于stack exchange,提问作者Lentemern

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 03:35:24