编译client.c时出现sharedMemory未定义引用错误求助
错误原因分析
你遇到的undefined reference to 'sharedMemory'错误本质有两个层面:
- 编译链接层面:
extern struct Player* sharedMemory[MAX_PLAYERS];仅告知编译器该变量在其他文件定义,但编译client时仅编译了client.c,未链接server的目标文件(server.o),链接器找不到变量的实际定义,因此报错。 - 跨进程设计错误:更核心的是,
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
额外注意点
- 共享内存detach时机:不能在设置信号后立即detach共享内存,否则信号处理函数访问时会触发错误,应在进程退出前再执行detach。
- 进程存活逻辑:添加
while(1) { pause(); }让client持续运行等待信号,避免进程刚启动就退出。 - 管道写入优化:避免写入整个数组的冗余字节,仅写入有效字符串长度(含终止符)。
内容的提问来源于stack exchange,提问作者noob_code
相关产品推荐
相关产品推荐

