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

编译client.c时出现sharedMemory未定义引用错误求助

错误原因分析

你遇到的undefined reference to 'sharedMemory'错误本质有两个层面:

  1. 编译链接层面:extern struct Player* sharedMemory[MAX_PLAYERS];仅告知编译器该变量在其他文件定义,但编译client时仅编译了client.c,未链接server的目标文件(server.o),链接器找不到变量的实际定义,因此报错。
  2. 跨进程设计错误:更核心的是,extern用于同一程序内的不同源文件共享变量,而server和client是独立进程,拥有各自的地址空间,无法通过extern直接访问另一个进程的变量——server里的sharedMemory是server进程的私有数据,client进程完全不可见。
解决方案

你已经使用System V共享内存(shmget/shmat)实现跨进程数据共享,这是正确方向。client无需依赖server的sharedMemory变量,应自行管理共享内存附着,直接操作共享内存区域即可。

步骤1:优化头文件

保留结构体定义,移除client不需要的extern声明:

// server.h
#ifndef SERVER_H
#define SERVER_H

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <signal.h>
#define MAXLINE 256
#define MAX_PLAYERS 3

struct inventory {
    int seed[14];
    int corp[14];
    int booster;
};

struct Player {
    char name[MAXLINE];
    struct inventory inventory[MAXLINE];
    int money[MAXLINE];
    int active;
    int pid;
};

extern int playerCount; // 仅server内部使用,client可移除

#endif

步骤2:修改client.c,移除对server的sharedMemory依赖

在client中自行定义共享内存指针数组,直接操作共享内存:

// client.c
#include "server.h"

int fd1, fd2;
int num;

// client端独立的共享内存指针数组
struct Player* sharedMemory[MAX_PLAYERS];

void select_conversation() {
    scanf("%d", &num);
    switch (num) {
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    case 4:
        break;
    case 5:
        break;
    case 6:
        break;
    default:
        break;
    }
}

void handleSignal(int signum);
void handlePlayerNamesSignal(int signum);

int main() {
    key_t key;
    int shmid;
    int keyFile = open("keyfile", O_RDONLY);

    if (keyFile == -1) {
        perror("keyopen");
        exit(EXIT_FAILURE);
    }

    if (read(keyFile, &key, sizeof(key)) != sizeof(key)) {
        perror("keyfile");
        close(keyFile);
        exit(EXIT_FAILURE);
    }
    close(keyFile);

    shmid = shmget(key, sizeof(struct Player) * MAX_PLAYERS, 0666);
    if (shmid == -1) {
        perror("shmget");
        exit(EXIT_FAILURE);
    }

    // 将共享内存附着到client自己的数组
    struct Player* shm_start = (struct Player*)shmat(shmid, NULL, 0);
    if (shm_start == (struct Player*)-1) {
        perror("shmat");
        exit(EXIT_FAILURE);
    }
    for (int i = 0; i < MAX_PLAYERS; ++i) {
        sharedMemory[i] = shm_start + i;
    }

    fd1 = open("pipe", O_WRONLY);
    fd2 = open("pipe1", O_RDONLY);

    if (fd1 == -1 || fd2 == -1) {
        perror("pipe error");
        exit(EXIT_FAILURE);
    }

    char playerName[MAXLINE];
    printf("input playername : ");
    fgets(playerName, MAXLINE, stdin);
    playerName[strcspn(playerName, "\n")] = '\0';

    // 仅写入有效字符串(含终止符),避免多余字节
    write(fd1, playerName, strlen(playerName) + 1);

    signal(SIGUSR2, handlePlayerNamesSignal);
    signal(SIGUSR1, handleSignal);

    // 循环等待信号,避免进程直接退出
    while(1) {
        pause();
    }

    // 退出前清理资源
    shmdt(shm_start);
    close(fd1);
    close(fd2);

    return 0;
}

void handleSignal(int signum) {
    if (signum == SIGUSR1) {
        printf("SIGUSR1. maingame start.\n");
        select_conversation();
    }
}

void handlePlayerNamesSignal(int signum) {
    if (signum == SIGUSR2) {
        printf("SIGUSR2. player name list:\n");
        for (int i = 0; i < MAX_PLAYERS; ++i) {
            if (sharedMemory[i]->active) {
                printf("Player[%d] : %s\n", i + 1, sharedMemory[i]->name);
            }
        }
    }
}

步骤3:正确编译命令

  • 编译server:gcc -o server server.c
  • 编译client:gcc -o client client.c
额外注意点
  1. 共享内存detach时机:不能在设置信号后立即detach共享内存,否则信号处理函数访问时会触发错误,应在进程退出前再执行detach。
  2. 进程存活逻辑:添加while(1) { pause(); }让client持续运行等待信号,避免进程刚启动就退出。
  3. 管道写入优化:避免写入整个数组的冗余字节,仅写入有效字符串长度(含终止符)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:35:30