使用GCC编译多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

