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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 01:15:32