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

C语言项目函数重复定义错误无法消除,求解决方案

问题根源

你遇到的链接错误核心原因是头文件中直接定义了函数实现(clear_session、send_request、serialize这三个函数)。C语言中,头文件被多个.c文件包含时,每个.c文件编译为目标文件(.o)时都会把这些函数的实现复制一份,链接阶段合并所有目标文件时,就会出现同一个函数被多次定义的冲突。

修复方案

1. 拆分头文件与实现文件

把logging.h中的函数实现移到单独的logging.c文件中,头文件只保留函数声明。

修改后的logging.h(仅保留声明)

#ifndef __UTILS_LOGGING_H__
#define __UTILS_LOGGING_H__

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> //open
#include <fcntl.h>  //flags for open
#include <unistd.h>

#define PIPENAME 256
#define BOXNAME 32
#define MSIZE 256
#define COMMAND 8

static const __uint8_t REGISTER_PUBLISHER = 1;
static const __uint8_t REGISTER_SUBSCRIBER = 2;
static const __uint8_t CREATE_BOX = 3;
static const __uint8_t REMOVE_BOX = 5;
static const __uint8_t LIST_BOX = 7;

static const char INVALID_SESSIONS[] = "Invalid number of sessions";
static const char PIPENAME_TOO_BIG[] = "The pipe's name has too many characters";
static const char INVALID_BOXNAME[] = "The box's name is invalid";
static const char INVALID_NUMBER_OF_ARGUMENTS[] = "Insufficient or too many arguments";
static const char INVALID_ARGUMENTS[] = "One of the arguments is invalid";
static const char UNEXISTENT_PIPE[] = "Pipe doesn't exist";
static const char EXISTENT_PIPE[] = "Pipe already exists";
static const char ERROR_WRITING_PIPE[] = "Error writing to pipe";
static const char SIGNAL_FAIL[] ="Failed to initialize signals";

typedef struct box{
    char boxname[BOXNAME];
    int hasWriter;
    int n_readers;
    struct box *next;
} box;

typedef struct req{
    int _code;
    char _client_pipe[PIPENAME];
    char _box_name[BOXNAME];
} request;

typedef enum {
    LOG_QUIET = 0,
    LOG_NORMAL = 1,
    LOG_VERBOSE = 2,
} log_level_t;

// 仅保留函数声明,去掉实现
void clear_session(int fd, char* fn);
void send_request(int tx, request *r1);
request *serialize(int code, char* client_pipe, char* box_name);

void sig_handler(int sig);
void set_log_level(log_level_t level);
extern log_level_t g_level;

#define INFO(...)                                                             
    do {                                                                      
        char buf[2048];                                                       
        snprintf(buf, 2048, __VA_ARGS__);                                     
        fprintf(stderr, "[INFO]:  %s:%d :: %s :: %s\n", __FILE__, __LINE__,    
                __func__, buf);                                               
    } while (0);

#define PANIC(...)                                                            
    do {                                                                      
        char buf[2048];                                                       
        snprintf(buf, 2048, __VA_ARGS__);                                     
        fprintf(stderr, "[PANIC]: %s:%d :: %s :: %s\n", __FILE__, __LINE__,    
                __func__, buf);                                               
        exit(EXIT_FAILURE);                                                   
    } while (0);

#define WARN(...)                                                             
    do {                                                                      
        if (g_level == LOG_NORMAL || g_level == LOG_VERBOSE) {                
            char buf[2048];                                                   
            snprintf(buf, 2048, __VA_ARGS__);                                 
            fprintf(stderr, "[WARN]:  %s:%d :: %s :: %s\n", __FILE__,          
                    __LINE__, __func__, buf);                                 
        }                                                                     
    } while (0);

#define LOG(...)                                                              
    do {                                                                      
        if (g_level == LOG_NORMAL || g_level == LOG_VERBOSE) {                
            char buf[2048];                                                   
            snprintf(buf, 2048, __VA_ARGS__);                                 
            fprintf(stderr, "[LOG]:   %s:%d :: %s :: %s\n", __FILE__,          
                    __LINE__, __func__, buf);                                 
        }                                                                     
    } while (0);

#define DEBUG(...)                                                            
    do {                                                                      
        if (g_level == LOG_VERBOSE) {                                         
            char buf[2048];                                                   
            snprintf(buf, 2048, __VA_ARGS__);                                 
            fprintf(stderr, "[DEBUG]: %s:%d :: %s :: %s\n", __FILE__,          
                    __LINE__, __func__, buf);                                 
        }                                                                     
    } while (0);

#endif // __UTILS_LOGGING_H__

创建logging.c文件(存放函数实现)

#include "logging.h"

//deletes fifo
void clear_session(int fd, char* fn){
    close(fd);
    unlink(fn);
}

/*writes to pipe tx a pointer with information*/
void send_request(int tx, request *r1) {
    ssize_t ret = write(tx, &r1, sizeof(r1)); 
    if (ret < 0) {
        fprintf(stdout, "ERROR: %s\n", ERROR_WRITING_PIPE);
        exit(EXIT_FAILURE);
    }
}

/*Returns a pointer to a struct containing the request*/
request *serialize(int code, char* client_pipe, char* box_name){
    request *r1 = (request*) malloc(sizeof(request));
    r1->_code  = code;
    strcpy(r1->_client_pipe, client_pipe); 
    strcpy(r1->_box_name, box_name); 
    return r1;
}

// 如果sig_handler和set_log_level有实现,同样放到这里
// void sig_handler(int sig) {
//     // 你的实现
// }

// void set_log_level(log_level_t level) {
//     // 你的实现
// }

// 全局变量g_level的定义也放到这里(如果之前未定义)
// log_level_t g_level = LOG_NORMAL;

2. 更新编译脚本(Makefile)

确保logging.c被纳入编译流程,比如在Makefile的源文件列表中添加utils/logging.c(根据你的目录结构调整路径):

# 添加logging.c到源文件列表
SRCS = mbroker/mbroker.c fs/operations.c fs/state.c utils/logging.c

OBJS = $(SRCS:.c=.o)
TARGET = mbroker

$(TARGET): $(OBJS)
    gcc -o $@ $(OBJS)

%.o: %.c
    gcc -c $< -o $@

clean:
    rm -f $(OBJS) $(TARGET)

3. 重新编译

先执行make clean清理旧目标文件,再执行make重新编译,链接错误即可解决。

额外提示
  • 头文件只能存放声明(函数原型、宏、类型定义、extern全局变量),不能放函数实现或全局变量定义(除非用static修饰,但static会导致每个.c文件生成独立副本,不符合共享函数的需求)。
  • 之前引入.c文件的操作会加剧重复定义问题,但你已删除该语句,当前核心问题已通过拆分头文件与实现文件解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:35:35