C语言头文件与实现文件分离时出现多重定义错误求助
问题描述
拆分代码为UDPRBPlib.h和UDPRBPlib.c后出现多重定义错误,错误信息如下:
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:14: multiple definition of `set'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:14: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:15: multiple definition of `get'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:15: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:16: multiple definition of `run'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:16: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:17: multiple definition of `stop'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:17: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:26: multiple definition of `server_struct_length'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:26: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPCurrentConvert': /home/UDPRBPlib.c:4: multiple definition of `RBPCurrentConvert'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:4: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o: in function `sendUDPMsg': /home/UDPRBPlib.c:12: multiple definition of `sendUDPMsg'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:12: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o: in function `UDPinit': /home/UDPRBPlib.c:54: multiple definition of `UDPinit'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:54: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPSendSetpt': /home/UDPRBPlib.c:76: multiple definition of `RBPSendSetpt'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:76: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o: in function `FTFToggle': /home/UDPRBPlib.c:106: multiple definition of `FTFToggle'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:106: first defined here /usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPSetRemote': /home/UDPRBPlib.c:122: multiple definition of `RBPSetRemote'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:122: first defined here collect2: error: ld returned 1 exit status
头文件 UDPRBPlib.h
#ifndef UDPRBPLIB_H #define UDPRBPLIB_H #include <math.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stdint.h> #include <unistd.h> uint8_t client_message[1]; uint8_t set = 0x73; uint8_t get = 0x67; uint8_t run = 0x18; uint8_t stop = 0x02; // INIT //#define DEBUGMODE 1 int socket_desc; struct sockaddr_in server_addr; char server_message[60]; // SEND MSG int server_struct_length = sizeof(server_addr); struct setpt{ uint16_t setptValue; // thing we're sending // [9] and [10] in RBPSendSetpt function uint8_t signflag; // RBP only takes positive numbers, the sign is to be communication in terms of charge and discharge signified by this flag uint8_t cktNum; int mode; // 1 for cc and 0 for cv int runOrStop; // 1 for run; 0 for stop int setOrGet; // 1 for set; 0 for get }; uint16_t RBPCurrentConvert(float x); int sendUDPMsg(); int UDPinit(); void RBPSendSetpt(const struct setpt tmp); void FTFToggle(const struct setpt tmp); void RBPSetRemote(const struct setpt tmp); #endif
实现文件 UDPRBPlib.c
#include "UDPRBPlib.h" // will convert x to the proper format uint16_t RBPCurrentConvert(float x){ x = fabs(x); x *= 100; x = roundf(x); uint16_t y = x; return y; } int sendUDPMsg(){ int length = sizeof(client_message)/sizeof(client_message[0]); #ifdef DEBUGMODE printf("Sending message:"); printf("\n"); #endif for(uint16_t i=0; i<sizeof(client_message); i++){ printf("0x%X\t", client_message[i]); if ((i + 1) % 15 == 0) printf("\n"); } // Send the message to server: if(sendto(socket_desc, client_message, sizeof(client_message), 0, (struct sockaddr*)&server_addr, server_struct_length) < 0){ printf("Unable to send message\n"); return -1; } // Receive the server's response: if(recvfrom(socket_desc, server_message, sizeof(server_message), 0, (struct sockaddr*)&server_addr, &server_struct_length) < 0){ printf("Error while receiving server's msg\n"); return -1; } printf("\nReceived message:"); for(uint16_t i=0; i<sizeof(server_message); i++){ if(i%15 == 0) printf("\n"); printf("0x%X\t", server_message[i]); } printf("\n"); // error check: see if what was returned was the same as what was sent for(int i = 0; i < length; i++){ if(server_message[i] != client_message[i]) printf("Error in server message at index %d\n", i); } // Close the socket: close(socket_desc); return 0; } int UDPinit(){ // Clean buffers: memset(server_message, '\0', sizeof(server_message)); //init //memset(client_message, '\0', sizeof(client_message)); // Create socket: in init socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(socket_desc < 0){ printf("Error while creating socket\n"); return -1; } printf("Socket created successfully\n"); // Set port and IP: init server_addr.sin_family = AF_INET; server_addr.sin_port = htons(36112); server_addr.sin_addr.s_addr = inet_addr("169.254.0.1"); return 0; } // assembles the message and returns a pointer to the message void RBPSendSetpt(const struct setpt tmp){ client_message[19]; client_message[0] = 0x01; // Rack Control Address client_message[1] = tmp.cktNum; client_message[2] = 0x43; // mandatory client_message[3] = 0x53; // mandatory if(tmp.setOrGet == 1) client_message[4] = set; else if(tmp.setOrGet == 0) client_message[4] = get; client_message[7] = 0x00; // current client_message[8] = 0x00; sendUDPMsg(); return; } // assemles the message in run OR stop state void FTFToggle(const struct setpt tmp){ client_message[5]; client_message[0] = 0x01; client_message[1] = tmp.cktNum; client_message[2] = 0x4C; client_message[3] = 0x52; if(tmp.runOrStop == 1) client_message[4] = run; else if(tmp.runOrStop == 0) client_message[4] = stop; sendUDPMsg(); return; } // assemles the message void RBPSetRemote(const struct setpt tmp){ client_message[6]; client_message[0] = 0x01; client_message[1] = tmp.cktNum; client_message[2] = 0x4C; client_message[3] = 0x30; if(tmp.setOrGet == 1) client_message[4] = set; else if(tmp.setOrGet == 0) client_message[4] = get; client_message[5] = 0x01; sendUDPMsg(); return; }
合并为单个文件可正常运行,拆分后出现上述错误,寻求解决方法。
解决方案
问题出在头文件里直接定义了全局变量,C语言里,如果头文件被多个源文件包含,全局变量的定义会被复制多次,链接器就会报多重定义错误。另外函数重复定义大概率是编译时重复编译了实现文件导致的。
1. 全局变量:头文件声明,实现文件定义
把所有全局变量从UDPRBPlib.h里移走,改用extern声明(告诉编译器“这个变量在别的地方定义”),然后在UDPRBPlib.c里真正定义这些变量。
修改UDPRBPlib.h的变量部分:
// 只声明,不定义 extern uint8_t client_message[]; extern uint8_t set; extern uint8_t get; extern uint8_t run; extern uint8_t stop; extern int socket_desc; extern struct sockaddr_in server_addr; extern char server_message[60]; extern int server_struct_length;
在UDPRBPlib.c开头加上变量定义:
#include "UDPRBPlib.h" // 真正定义全局变量 uint8_t client_message[20]; // 改成20,因为代码里用到了索引19,原来的长度1会越界 uint8_t set = 0x73; uint8_t get = 0x67; uint8_t run = 0x18; uint8_t stop = 0x02; int socket_desc; struct sockaddr_in server_addr; char server_message[60]; int server_struct_length = sizeof(server_addr);
2. 函数重复定义:确保实现文件只编译一次
头文件里的函数是声明(只有原型,没有代码),这部分没问题。但如果编译时把UDPRBPlib.c多次加入编译命令,就会导致重复定义。比如正确的编译命令应该是:
gcc main.c UDPRBPlib.c -o your_program -lm
(-lm是链接数学库,因为用到了fabs和roundf)
3. 修正数组越界问题
原来代码里的client_message[19];这种写法没用,不会改变数组大小,反而会导致越界。所以直接把client_message定义成足够大的长度(比如20),每次发送前用memset清空缓冲区,避免残留数据干扰。
这样修改后,重新编译就能解决多重定义的问题了。
内容的提问来源于stack exchange,提问作者techandmoretech
相关产品推荐
相关产品推荐

