如何修复C/Unix程序中“assignment makes pointer from integer without a cast”警告
问题分析与修复方案
嘿,我帮你找到了问题的根源——这是C语言里很容易踩的运算符优先级坑!你的编译警告和段错误都是因为这个,咱们一步步来解决:
1. 编译警告与段错误的核心原因
在C语言中,==(相等判断)的优先级比=(赋值)高,所以你写的这类代码:
if(id_mem = shmget(key_mem,SHMEMSIZE,0) == -1)
实际执行顺序完全不是你想的那样:它会先计算shmget(...) == -1,得到一个布尔值(0或1,属于整数类型),然后把这个整数赋值给id_mem。
这直接导致两个严重问题:
id_mem拿到的不是正确的共享内存ID,而是0或1,后续用这个错误ID调用shmat,返回的地址肯定无效,自然触发段错误- 对于
addr_mem = shmat(...) == (void*)-1,同样是把布尔值(整数)赋值给指针类型的addr_mem,所以编译器会抛出“assignment makes pointer from integer without a cast”的警告
2. 最关键的修复:加括号改变优先级
所有这类“赋值+判断”的语句,都要给赋值表达式套上括号,确保先完成赋值,再判断结果是否为-1:
生产者代码的修复点
把原来的:
if(id_mem = shmget(key_mem,SHMEMSIZE,0) == -1) if(addr_mem =shmat(id_mem,NULL,0) == (void *)-1) if(id_sem = semget(key_sem,2,0)== -1)
改成:
if( (id_mem = shmget(key_mem,SHMEMSIZE,0)) == -1 ) if( (addr_mem = shmat(id_mem,NULL,0)) == (void *)-1 ) if( (id_sem = semget(key_sem,2,0)) == -1 )
消费者代码的修复点
同样修复优先级问题,比如:
// 修复前 if(id_mem = shmget(key_mem,SHMEMSIZE,IPC_CREAT|0666) == -1) // 修复后 if( (id_mem = shmget(key_mem,SHMEMSIZE,IPC_CREAT|0666)) == -1 )
另外,消费者里还有个小错误:shmctl(id_sem, IPC_RMID, NULL)是错的,shmctl是用来操作共享内存的,应该传入共享内存IDid_mem,而不是信号量IDid_sem,这个也要修正。
3. 额外的细节优化
- 生产者里的
scanf("%[^\n]", ...)容易被残留的换行符影响,改成scanf(" %[^\n]", ...)(注意前面的空格),可以自动跳过输入前的空白字符,避免直接按回车导致的异常 - 原来的
getc(stdin)可以去掉,因为上面的scanf已经处理了换行问题
修复后的完整代码
修复后的生产者代码
#include <errno.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <stdio.h> #define SHMEMSIZE 4096 int main() { key_t key_mem = 6868; key_t key_sem = 3232; int id_mem; int id_sem; void *addr_mem; struct sembuf param[1]; // 修复运算符优先级:赋值表达式加括号 if( (id_mem = shmget(key_mem, SHMEMSIZE, 0)) == -1 ) { perror("Errore1: 共享内存获取失败"); return -1; } if( (addr_mem = shmat(id_mem, NULL, 0)) == (void *)-1 ) { perror("Errore2: 共享内存挂载失败"); return -1; } if( (id_sem = semget(key_sem, 2, 0)) == -1 ) { perror("Errore3: 信号量获取失败"); shmdt(addr_mem); return -1; } while(1) { // P操作:获取空缓冲区信号量 param[0].sem_num = 1; param[0].sem_op = -1; param[0].sem_flg = 0; if(semop(id_sem, param, 1) == -1) { perror("Errore6: 信号量操作失败"); return -1; } printf("Scrivi messaggio: "); // 前面加空格跳过空白字符,避免残留换行影响 if( scanf(" %[^\n]", (char *)addr_mem) == 0 ) *((char *)addr_mem) = '\0'; // V操作:通知有数据可读取 param[0].sem_num = 0; param[0].sem_op = 1; param[0].sem_flg = 0; if(semop(id_sem, param, 1) == -1) { perror("Errore7: 信号量操作失败"); return -1; } } shmdt(addr_mem); return 0; }
修复后的消费者代码
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <stdio.h> #define SHMEMSIZE 4096 union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; int main() { key_t key_mem = 6868; key_t key_sem = 3232; int id_mem; int id_sem; void *addr_mem; union semun arg; struct sembuf param[1]; // 修复运算符优先级 if( (id_mem = shmget(key_mem, SHMEMSIZE, IPC_CREAT|0666)) == -1 ) { perror("Errore1: 共享内存创建失败"); return -1; } if( (addr_mem = shmat(id_mem, NULL, 0)) == (void *)-1 ) { perror("Errore2: 共享内存挂载失败"); shmctl(id_mem, IPC_RMID, NULL); return -1; } if( (id_sem = semget(key_sem, 2, IPC_CREAT|0666)) == -1 ) { perror("Errore3: 信号量创建失败"); shmctl(id_mem, IPC_RMID, NULL); shmdt(addr_mem); return -1; } // 初始化数据就绪信号量(0:无数据) arg.val = 0; if(semctl(id_sem, 0, SETVAL, arg) == -1) { perror("Errore4: 信号量初始化失败"); semctl(id_sem, -1, IPC_RMID, arg); shmctl(id_mem, IPC_RMID, NULL); // 修复:使用共享内存ID shmdt(addr_mem); return -1; } // 初始化空缓冲区信号量(1:有一个空缓冲区) arg.val = 1; if(semctl(id_sem, 1, SETVAL, arg) == -1) { perror("Errore5: 信号量初始化失败"); semctl(id_sem, -1, IPC_RMID, arg); shmctl(id_mem, IPC_RMID, NULL); // 修复:使用共享内存ID shmdt(addr_mem); return -1; } while(1) { // P操作:等待数据就绪 param[0].sem_num = 0; param[0].sem_op = -1; param[0].sem_flg = 0; if(semop(id_sem, param, 1) == -1) { perror("Errore6: 信号量操作失败"); return -1; } printf("Il messaggio scritto è: %s\n", (char *)addr_mem); // V操作:释放空缓冲区 param[0].sem_num = 1; param[0].sem_op = 1; param[0].sem_flg = 0; if(semop(id_sem, param, 1) == -1) { perror("Errore7: 信号量操作失败"); return -1; } } // 理论上不会执行到这里,加上清理代码更严谨 semctl(id_sem, -1, IPC_RMID, arg); shmctl(id_mem, IPC_RMID, NULL); shmdt(addr_mem); return 0; }
运行步骤
- 先启动消费者程序:它会负责创建共享内存和信号量,并初始化信号量的初始值
- 再启动生产者程序:输入消息后,消费者会立刻输出你输入的内容
这样修复后,编译警告会消失,生产者也不会再触发段错误,共享内存可以正常完成读写操作啦!
内容的提问来源于stack exchange,提问作者ABC
相关产品推荐
相关产品推荐

