C语言链接文件时出现多重定义错误,头文件保护无效求排查
问题排查:全局变量多重定义的链接错误
问题背景
完成计算机编程课程作业时遭遇链接错误:gcc提示count和booksCatalog存在多重定义。已添加头文件保护,但问题仍未解决,相关代码如下:
原代码文件
book.h
#ifndef BOOK_H #define BOOK_H #include <stdio.h> typedef enum shelf{Shelf1=1,Shelf2=2,Shelf3=3,Shelf4=4} SHELF; typedef struct book{ int ID; SHELF shelfNum; float price; } BOOK; BOOK newBook(int ID, SHELF shelfNum, float price); void printBook(BOOK book1); #endif
book.c
#include "book.h" BOOK newBook(int ID, SHELF shelfNum, float price) { BOOK newbook = {ID, shelfNum, price}; return newbook; } void printBook(BOOK book1) { printf("Book ID : %d\n", book1.ID); printf("Book shelf number : %d\n", book1.shelfNum); printf("Price of Book: %f\n\n",book1.price); return; }
catalog.h(错误根源文件)
#ifndef CATALOG_H #define CATALOG_H #include "book.h" #define MAX_SIZE 100 // 错误:在头文件中直接定义全局变量 BOOK booksCatalog[MAX_SIZE]; int count; void addBookToCatalog(BOOK book1); void printBookCatalog(); void sortBookCatalogOnID(); #endif
catalog.c
#include "catalog.h" void addBookToCatalog(BOOK book1) { if (count<MAX_SIZE) { booksCatalog[count]=book1; count++; } else printf("Catalog is full!"); return; } void printBookCatalog() { for (int i=0; i<count; i++) { printBook(booksCatalog[i]); } return; } void sortBookCatalogOnID() { int min; for (int i=0; i<count-1; i++) { min=i; for (int j=i+1; j<count; j++) { if ((booksCatalog[j].ID)<(booksCatalog[min].ID)) min=j; } BOOK temp = booksCatalog[i]; booksCatalog[i]=booksCatalog[min]; booksCatalog[min]=temp; } return; }
main.c
#include "catalog.h" #include "book.h" int main() { count = 0; BOOK book1 = newBook(1847, Shelf3, 8768.95); BOOK book2 = newBook(5984, Shelf1, 7845.25); BOOK book3 = newBook(6325, Shelf2, 3154.47); BOOK book4 = newBook(5843, Shelf2, 1487.51); BOOK book5 = newBook(7894, Shelf2, 541.29); addBookToCatalog(book1); addBookToCatalog(book2); addBookToCatalog(book3); addBookToCatalog(book4); addBookToCatalog(book5); printBookCatalog(); sortBookCatalogOnID(); printBookCatalog(); return 0; }
错误原因
头文件保护(#ifndef/#define/#endif)仅能防止单个源文件重复包含同一头文件,无法解决多个源文件包含同一头文件时的全局变量重复定义问题。
你在catalog.h中直接定义了全局变量booksCatalog和count,当main.c和catalog.c都包含该头文件时,两个源文件会各自生成一份变量定义。链接阶段编译器发现同一变量存在多份定义,因此抛出多重定义错误。
解决方法
遵循C语言编码规范:头文件中仅声明全局变量,在单个源文件中定义全局变量。
步骤1:修改catalog.h,将变量定义改为extern声明
#ifndef CATALOG_H #define CATALOG_H #include "book.h" #define MAX_SIZE 100 // 用extern声明变量,告知编译器变量在其他文件中定义 extern BOOK booksCatalog[MAX_SIZE]; extern int count; void addBookToCatalog(BOOK book1); void printBookCatalog(); void sortBookCatalogOnID(); #endif
步骤2:在catalog.c中定义全局变量并初始化
在catalog.c开头添加变量定义,同时初始化count为0(避免未初始化全局变量的风险):
#include "catalog.h" // 全局变量仅在此处定义,整个程序中仅一份实例 BOOK booksCatalog[MAX_SIZE]; int count = 0; // 原函数实现保持不变 void addBookToCatalog(BOOK book1) { if (count<MAX_SIZE) { booksCatalog[count]=book1; count++; } else printf("Catalog is full!"); return; } void printBookCatalog() { for (int i=0; i<count; i++) { printBook(booksCatalog[i]); } return; } void sortBookCatalogOnID() { int min; for (int i=0; i<count-1; i++) { min=i; for (int j=i+1; j<count; j++) { if ((booksCatalog[j].ID)<(booksCatalog[min].ID)) min=j; } BOOK temp = booksCatalog[i]; booksCatalog[i]=booksCatalog[min]; booksCatalog[min]=temp; } return; }
步骤3:修改main.c,移除重复初始化
由于count已在catalog.c中初始化,删除main.c中的count = 0;语句:
#include "catalog.h" #include "book.h" int main() { BOOK book1 = newBook(1847, Shelf3, 8768.95); BOOK book2 = newBook(5984, Shelf1, 7845.25); BOOK book3 = newBook(6325, Shelf2, 3154.47); BOOK book4 = newBook(5843, Shelf2, 1487.51); BOOK book5 = newBook(7894, Shelf2, 541.29); addBookToCatalog(book1); addBookToCatalog(book2); addBookToCatalog(book3); addBookToCatalog(book4); addBookToCatalog(book5); printBookCatalog(); sortBookCatalogOnID(); printBookCatalog(); return 0; }
验证修改
重新编译链接,多重定义错误将被修复。此时booksCatalog和count仅在catalog.c中有一份定义,其他文件通过extern声明引用该定义,符合C语言的链接规则。
内容的提问来源于stack exchange,提问作者ErrorEliminator
相关产品推荐
相关产品推荐

