C语言中如何将自定义类型静态数组传参给另一个自定义对象
问题描述
我在C语言中尝试将自定义类型的静态数组传递给另一个自定义结构体,定义了如下结构体:
typedef struct sem_holder { sem_t *writer_sem; sem_t *reader_sem; } sem_holder; typedef struct worker_arg { unsigned int nsegments; size_t segsize; sem_holder *sems; } worker_arg;
最初传递sems数组时遇到指针类型不匹配的编译错误:
- 使用
&sems时,提示初始化sem_holder*类型不兼容; - 使用
sems时,提示sem_holder*与sem_holder**类型不兼容。
修改代码后传参成功,但调用sem_open初始化信号量时设置初始值为10,实际运行时信号量值始终为0,求解决思路。修改后的代码如下:
// char *processes[nsegments]; sem_holder sems[nsegments]; char sem_write_name[21]; char sem_read_name[21]; sem_t *writer_sem; sem_t *reader_sem; ftruncate(DATA_CHANNEL_ID, segsize * nsegments); for (int i = 0; i < nsegments; i++) { // Map subsection of data-channel to an array in proxy's virtual memory // processes[i] = mmap(NULL, sizeof(segsize), PROT_READ | PROT_WRITE, MAP_SHARED, DATA_CHANNEL_ID, i * segsize); // Dynamically create reader and writer names snprintf(sem_write_name, 21, "%dw", i); snprintf(sem_read_name, 21, "%dr", i); // Create a likewise array for semaphores writer_sem = sem_open(sem_write_name, O_CREAT, 0660, 10); if (writer_sem == SEM_FAILED) printf("FAILED\n"); sems[i].writer_sem = writer_sem; reader_sem = sem_open(sem_read_name, O_CREAT, 0660, 10); if (reader_sem == SEM_FAILED) printf("FAILED\n"); sems[i].reader_sem = reader_sem; } // Initialize worker arg worker_arg worker_arg = {.nsegments = nsegments, .segsize = segsize, .sems = sems};
解决思路
一、数组传参类型问题的说明
静态数组sems[nsegments]的数组名sems会隐式转换为指向数组首元素的指针,类型是sem_holder*,和worker_arg的sems成员类型完全匹配。你最初碰到的类型不兼容错误,大概率是之前误将worker_arg的sems成员定义为sem_holder**,或者传参时多取了一次地址。现在修改后的代码里.sems = sems的写法是完全正确的,不需要加&。
二、信号量初始值异常的排查步骤
- 检查信号量是否已存在:
sem_open仅在信号量不存在时才会使用你传入的初始值。如果之前运行程序时创建过同名信号量且未清理,O_CREAT标志会直接打开现有信号量,忽略初始值。- 处理方案:
- 在
sem_open中添加O_EXCL标志(即O_CREAT | O_EXCL),这样如果信号量已存在会直接报错,方便快速定位; - 程序退出时,先调用
sem_close关闭信号量,再调用sem_unlink删除命名信号量,避免残留; - 手动清理系统中已存在的同名信号量(用
ipcs命令查看,ipcrm命令删除)。
- 在
- 处理方案:
- 完善错误日志:当前代码仅打印"FAILED",无法定位具体错误原因。建议替换为
perror("sem_open failed"),这样可以输出系统错误信息,确认信号量是否真的创建成功。 - 排查信号量操作逻辑:如果其他线程/进程在你检查信号量值之前执行了
sem_wait操作,会将信号量计数减到0。要确保在读取信号量值前,没有对其进行P操作。 - 验证权限设置:
0660的权限是否符合当前进程的运行上下文?如果权限不足,可能导致信号量访问异常,不过这种情况通常sem_open会直接失败,通过perror可以快速排查。
内容的提问来源于stack exchange,提问作者Josh Voytek
相关产品推荐
相关产品推荐

